order by null用途是强制对查询结果禁用排序。通过explain检查查询语句时候,如果看到Extra列中有Using filesort,这是对性能有一定影响的,特别是使用了group by时,就算你没有显示的指定order by,mysql会默认按照分组字段进行排序。某些情况下是没有必要使用排序的,例如在处理表报数据的时候(把原始表数据统计后插入到一个用于报表查询的表),则完全可以可以使用order by null来取消排序。如:
insert into reportTable(day, clicks, revenue)
select day, count(*), sum(revenue) from clickOriginTalbe
group by day
order by null
有两种方法可以在命令行下执行sql命令。第一种是使用“-e“参数来指定需要执行的sql语句;第二种是通过管道的方式。语法及例子如下:
1、
MYSQL_HOME/bin/mysql -u用户名 -p密码 -D数据库名 -e"sql 语句"
/usr/local/mysql/bin/mysql -uroot -p123456 -Dmysql -e"select host,user from user";
2、
echo "sql 语句" | MYSQL_HOME/bin/mysql -u用户名 -p密码 -D数据库名
echo "select host,user from user" | /usr/local/mysql/bin/mysql -uroot -p123456 -Dmysql
上面命令执行的结果如下图。从图中可以看到二者的显示结果有些不一样。
使用场景多用在脚本中,例如定期执行存储过程、load data infile以及删除老数据等。
自mysql 5.1.3起开始支持分区功能。mysql表中存储的记录和表对应的索引信息,最后都是以文件的方式存储在计算机的硬盘上的,有了分区功能,就可以按照一定的分区规则把这些记录分布到不同的数据文件上,目前分区规则有四种,分别是RANGE、LIST、HASH和KEY,另外通过DATA DIRECTORY和INDEX DIRECTORY选项可以把不同的分区数据文件分散到不同的磁盘上,从而进步一提高系统的IO吞吐量。因此按照业务逻辑设计好了分区,可以大大提高查询效率,而且删除数据可能也会很容易。但是分区也有一些限制:1、主键或者唯一索引必须包含分区字段;2、只能通过int类型的字段或者返回int类型的表达式来分区;3、单表最多只能有1024个分区。
默认mysql是开启了分区功能的,可以通过下述查询查看结果:
show variables like '%partition%';
+-------------------+-------+
| Variable_name | Value |
+-------------------+-------+
| have_partitioning | YES |
+-------------------+-------+
//YES 表示开启
下面也range规则为例介绍一下分区常用的命令。
1、创建分区。可以在创建表的同时创建,也可以在表创建后追加分区。
drop table if exists `netingcn_com`;
create table `netingcn_com` (
`id` int(11) unsigned not null auto_increment,
`day` int(11) not null default 0,
primary key (`id`, `day`)
) engine=innodb default charset=utf8 auto_increment=1;
alter table `netingcn_com` partition by range(`day`) (
partition p_2012 values less than (20130000),
partition p_2013 values less than (20140000)
);
或
drop table if exists `netingcn_com`;
create table `netingcn_com` (
`id` int(11) unsigned not null auto_increment,
`day` int(11) not null default 0,
primary key (`id`, `day`)
) engine=innodb default charset=utf8 auto_increment=1
partition by range(`day`) (
partition p_2012 values less than (20130000),
partition p_2013 values less than (20140000)
);
可以explain命令查看分区是否创建成功
explain partitions select * from netingcn_com where day = 20130412;
+----+-------------+--------------+------------+-------+
| id | select_type | table | partitions | type |
+----+-------------+--------------+------------+-------+
| 1 | SIMPLE | netingcn_com | p_2013 | index |
+----+-------------+--------------+------------+-------+
2、增加或删除分区。注意:删除分区的同时,该分区的所有数据也会别删除。
增加分区
alter table netingcn_com add partition (
partition p_2014 values less than (20150000)
);
删除分区
alter table netingcn_com drop partition p_2012;
3、重新分区。注意:hash和key分区规则不能用REORGANIZE来重新分区
alter table netingcn_com reorganize partition p_2013,p_2014 into (partition p_2014 values less than (20150000));
更多关于mysql 分区功能可以参考:http://dev.mysql.com/tech-resources/articles/mysql_55_partitioning.html
今天在本机的mysql数据目录下发现了许多类似hostname-relay-bin.0000*的文件,该文件一般是在mysql slave实例上存在。主要用途是记录主从同步的信息,正常情况下会自动删除的。
本机未配置过master、slave,对于其来源还真不太清楚。既然是用在slave上的,那就可以放心的删除。删除master实例上的日志文件用reset master,对于slave实例就使用命令:
reset slave
当开启bin-log日志时,会生成很多mysql-bin.0000*类似的文件,而且可能会占用很大的硬盘空间。对于自己的测试机器或硬盘比较紧张的vps,而又不需要做master,slave的配置,完全可以关闭日志功能。
关闭操作很简单,找到配置文件my.cnf,对于linux,一般默认在/etc目录下,打开此文件,使用井号(#)注释掉如下两个配置项目即可。
log-bin=mysql-bin
binlog_format=mixed
配置修改好后需要重启mysqld服务才能生效。可能在重启时候会收到一个错误,“ERROR 1186 (HY000): Binlog closed, cannot RESET MASTER”,解决办法是先登入到mysql命令行中执行 reset master 即可。reset master的用途就是删除先前所以的bin-log日志文件。所以在master、slave配置环境中慎用此命令。
mysql使用select count(*) from table_name可以查询某个表的总记录数。想快速的知道数据库中所有表的记录数信息怎么办?如果使用mysql的版本在5.0及以上,可以通过查询information_schema库中的tables表来获取,该表中使用table_rows记录表的行数信息。例如查看库testdb中所有表的记录数:
use information_schema;
select table_name,table_rows from tables
where TABLE_SCHEMA = 'testdb'
order by table_rows desc;
不过需要注意的是,对于InnoDB表,table_rows行计数仅是大概估计值。
另外一种办法还是借助information_schema库的tables表,来拼接出一个条sql语句,例如:
use information_schema;
select concat(
'select "',
TABLE_name,
'", count(*) from ',
TABLE_SCHEMA,
'.',
TABLE_name,
' union all'
) from tables
where TABLE_SCHEMA='testdb';
把生成的结果手动加工一下就行了,起码比一张张表去拼写要来的快。
mysql中内置函数date_add和date_sub能对指定的时间进行增加或减少一个指定的时间间隔,语法如下:
DATE_ADD(date,INTERVAL expr type)
DATE_SUB(date,INTERVAL expr type)
其中date是指定的日期,INTERVAL为关键词,expr是具体的时间间隔,type是时间单位。注意:type可以复合型的,比如YEAR_MONTH。如果type不是复合型的,DATE_ADD和DATE_SUB其实可以通用,因为expr可以为一个负数。可用的type如下表:
MICROSECOND |
间隔单位:毫秒 |
SECOND |
间隔单位:秒 |
MINUTE |
间隔单位:分钟 |
HOUR |
间隔单位:小时 |
DAY |
间隔单位:天 |
WEEK |
间隔单位:星期 |
MONTH |
间隔单位:月 |
QUARTER |
间隔单位:季度 |
YEAR |
间隔单位:年 |
SECOND_MICROSECOND |
复合型,间隔单位:秒、毫秒,expr可以用两个值来分别指定秒和毫秒 |
MINUTE_MICROSECOND |
复合型,间隔单位:分、毫秒 |
MINUTE_SECOND |
复合型,间隔单位:分、秒 |
HOUR_MICROSECOND |
复合型,间隔单位:小时、毫秒 |
HOUR_SECOND |
复合型,间隔单位:小时、秒 |
HOUR_MINUTE |
复合型,间隔单位:小时分 |
DAY_MICROSECOND |
复合型,间隔单位:天、毫秒 |
DAY_SECOND |
复合型,间隔单位:天、秒 |
DAY_MINUTE |
复合型,间隔单位:天、分 |
DAY_HOUR |
复合型,间隔单位:天、小时 |
YEAR_MONTH |
复合型,间隔单位:年、月 |
对应复合型的type,需要使用引号对两个参数进行引用起来,中间用任何非数字字符作为间隔即可,并且不能使用负数。但是时间间隔只指定了一个值,那么也能正常工作,但是对应XXX_YYY使用的单位为YYY,也就相当于单一单位的type,同时可以使用负数。复合型的用法如下:
mysql> select date_add('2013-01-18', interval '1 2' YEAR_MONTH);
+-----------------------------------------------------+
| date_add('2013-01-18', interval '1 2' YEAR_MONTH) |
+-----------------------------------------------------+
| 2014-03-18 |
+-----------------------------------------------------+
mysql> select date_add('2013-01-18', interval '1-2' YEAR_MONTH);
+----------------------------------------------------+
| date_add('2013-01-18', interval '1-2' YEAR_MONTH) |
+----------------------------------------------------+
| 2014-03-18 |
+----------------------------------------------------+
mysql> select date_add('2013-01-18', interval '1,2' YEAR_MONTH);
+---------------------------------------------------+
| date_add('2013-01-18', interval '1,2' YEAR_MONTH) |
+---------------------------------------------------+
| 2014-03-18 |
+---------------------------------------------------+
mysql> select date_add('2013-01-18', interval 1 YEAR_MONTH);
+-----------------------------------------------+
| date_add('2013-01-18', interval 1 YEAR_MONTH) |
+-----------------------------------------------+
| 2013-02-18 |
+-----------------------------------------------+
mysql> select date_add('2013-01-18', interval -1 YEAR_MONTH);
+------------------------------------------------+
| date_add('2013-01-18', interval -1 YEAR_MONTH) |
+------------------------------------------------+
| 2012-12-18 |
+------------------------------------------------+
mysql内置的ifull函数可以用在查询时候为NULL值字段给一个默认值,例如:
select ifnull(col1, 'default-value'), col2 from test;
当test表的col1字段为NULL时,数据库返回的结果就为default-value,否则就返回本身的值。但是当col1字段的值为空字符串(”),由于空字符不是NULL,因此返回的结果还是空字符串。如果需要把空字符串或NULL值都用default-value代替,显然ifnull是不行,不过使用case when语句能搞定,示例如下:
select c1,
(case when c2 = '' or c2 is null then 'default-value' else c2 end)
from test;
Mysql可以使用AUTO_INCREMENT来设定主键的值为自增长的,其默认值是1,如果想把它的初始值设置为1000,比较笨的办法是先插入一条记录并指定主键的值为999,然后delete改行记录,例如:
insert into test(pk) values(999);
delete from test where pk = 999;
更好的方法是使用alter的方法来直接修改,例如:
alter table test AUTO_INCREMENT = 200;
需要根据某个时间点来统计数量,例如统计每天网站的访问量,本人以前的做法是先查询当前有没有记录,如果存在就更新访问量的值,否则就插入一条。其实在Mysql中可以一条SQL语句来搞定,只要使用ON DUPLICATE KEY UPDATE即可。例如:
insert into daypv(day,cnt) values('2012-11-22',1)
on duplicate key update cnt = cnt + 1;
如果insert 末尾指定了on duplicate key update,插入数据会导致一个primary key或unique索引出现重复,那么就对已经存在的行执行update操作,条件就是primary key或unique索引。
对于一次插入一条记录没有问题,如果一次插入多条记录,其中某些可能会造成primary key或unique索引重复,那该如何处理呢。其实和单条处理类似,只要在后面使用values函数即可,例如:
insert into daypv(day,cnt)
values('2012-11-22',1),
('2012-11-23',2),
('2012-11-24',3),
('2012-11-25',4)
on duplicate key update cnt = cnt + values(cnt);
上述 “cnt = cnt + values(cnt)”中第一个是cnt指更新的字段,第二个指原来的值,第三个是上面insert对应行中指定的cnt的值,例如2012-11-24记录已经存在,cnt的原始值为5,那么执行上述sql后,2012-11-24的cnt就为8 ( 3 + 5)。
另外需要注意的是 ON DUPLICATE KEY UPDATE 是Mysql特有的,不是标准的SQL语法。