由where 1 =1 引发的思考
最近工作上被说了
说代码中不能用 where 1=1,当时觉得是应该可以用的,但是找不到什么理据,
而且mysql 语句优化这方面确实很薄弱
感觉自己mysql方面是知识还是不够哇
得好好研究研究
还有发现 很多知识点 光看的话根本记不住,也不深刻。还是得亲手实践下
so ~~~ 挫折越多进步越快
1、关于sql语句大小问题
1)mysql默认情况下没有设置 root用户密码
给mysql的root用户设置密码先
[[email protected] ~]$ mysqladmin -uroot password "root"
2)默认情况下sql语句是限制在1M以内
max_allowed_packet 表示sql最大为1M mysql> show VARIABLES like ‘%max_allowed_packet%‘; +--------------------------+------------+ | Variable_name | Value | +--------------------------+------------+ | max_allowed_packet | 1048576 | | slave_max_allowed_packet | 1073741824 | +--------------------------+------------+ 2 rows in set (0.00 sec)
这里最好改大,如果太小的话sql语句超过1M会导致sql语句执行失败
3)
[[email protected] ztao]# vim /etc/my.cnf 添加红色的那一行 [mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock user=mysql # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 max_allowed_packet = 160M [mysqld_safe] log-error=/var/log/mysqld.log pid-file=/var/run/mysqld/mysqld.pid
4)
然后重启mysql 在查看下
160M = 160*1024*1024=167772160
mysql> show VARIABLES like ‘%max_allowed_packet%‘; +--------------------------+------------+ | Variable_name | Value | +--------------------------+------------+ | max_allowed_packet | 167772160 | | slave_max_allowed_packet | 1073741824 | +--------------------------+------------+ 2 rows in set (0.00 sec)
这样能支持你一条sql语句在160M以内
2、在window下写的脚本文件放在linux上执行失败
在Windows下写了一个shell脚本,
上传到Linux下执行时经常会报这种错误:
[[email protected] test]
# ./test.sh
-
bash: .
/
test.sh:
/
bin
/
sh^M: bad interpreter: No such
file
or
directory
主要原因是test.sh是我在windows下编辑然后上传到linux系统里执行的。
windows下编辑的.sh文件的格式为dos格式。
而linux只能执行格式为unix格式的脚本。
因为在dos/window下按一次回车键实际上输入的是“回车(CR)”和“换行(LF)”,
而Linux/unix下按一次回车键只输入“换行(LF)”,所以修改的sh文件在每行都会多了一个CR,所以Linux下运行时就会报错找不到命令。
我们可以通过vi编辑器来查看文件的format格式。步骤如下:
1.
首先用vi命令打开文件
2.
在vi命令模式中使用 :
set
ff 命令
可以看到改文件的格式为
fileformat
=
dos
3.
修改文件
format
为unix
使用vi
/
vim修改文件
format
命令::
set
ff
=
unix
或者::
set
fileformat
=
unix
然后:wq保存退出就可以了
3、通过脚本创建表并插入数据
1)通过shell创建表
#!/bin/sh dbenv=dev if [ "${dbenv}" = "dev" ]; then mysql_user=root mysql_pass=root mysql_host= fi if [ "${dbenv}" = "idc" ]; then mysql_user=root mysql_pass=root mysql_host="-h 10.10.10.10" fi mysql_cmd="mysql -u${mysql_user} -p${mysql_pass} ${mysql_host} --default-character-set=utf8" ${mysql_cmd}<<EOF use test; drop table if exists t_user; create table t_user ( f_uin bigint(20) NOT NULL auto_increment, f_name varchar(256) NOT NULL DEFAULT ‘‘, f_createtime datetime not null default ‘0000-00-00 00:00:00‘, f_status int(11) NOT NULL DEFAULT ‘0‘, f_rangenum int(11) NOT NULL DEFAULT ‘0‘, PRIMARY KEY (f_uin) )ENGINE=InnoDB DEFAULT CHARSET=utf8; EOF echo "create table t_user ok"
2)通过python脚本来创建sql脚本
#!/usr/bin/python #-*-coding:UTF-8-*- import sys def Insert(num): if(num<=10000000): str = "insert into t_user (f_name,f_createtime,f_status,f_rangenum) values " for i in range(num): name = "zhantao_%d"%i status = 1 rangenum = i if(i==0): strsql = "(‘%s‘,now(),%d,%d)"%(name,status,rangenum) else: strsql = ",(‘%s‘,now(),%d,%d)"%(name,status,rangenum) str += strsql f = open("insert.sql","w") f.write(str) f.close if __name__ == ‘__main__‘: #num = int(sys.argv[1]) Insert(1000000)
可以看到创建出来的sql脚本 一个就33兆 如果前面没有修改sql语句最大长度,是肯定执行不了的
[ztao
@localhost
0418]$ ll -alh
total 33M
drwxrwxr-x 2 ztao ztao 4.0K Apr 18 20:16 .
drwxrwxr-x 3 ztao ztao 4.0K Apr 18 20:02 ..
-rwxrwxr-x 1 ztao ztao 733 Apr 18 20:03 create_table.sh
-rwxrwxr-x 1 ztao ztao 538 Apr 18 20:10 insert.py
-rw-rw-r-- 1 ztao ztao 33M Apr 18 20:11 insert.sql
3)把数据导入到sql里面
这里面导入的五次,一次100w
因为主键是自增的所以重复插入不会产生冲突
mysql> use test Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> source /home/ztao/Work/Test/0418/insert.sql Query OK, 1000000 rows affected (11.77 sec) Records: 1000000 Duplicates: 0 Warnings: 0 mysql> source /home/ztao/Work/Test/0418/insert.sql Query OK, 1000000 rows affected (8.90 sec) Records: 1000000 Duplicates: 0 Warnings: 0 mysql> source /home/ztao/Work/Test/0418/insert.sql Query OK, 1000000 rows affected (8.43 sec) Records: 1000000 Duplicates: 0 Warnings: 0 mysql> source /home/ztao/Work/Test/0418/insert.sql Query OK, 1000000 rows affected (8.28 sec) Records: 1000000 Duplicates: 0 Warnings: 0 mysql> source /home/ztao/Work/Test/0418/insert.sql Query OK, 1000000 rows affected (7.87 sec) Records: 1000000 Duplicates: 0 Warnings: 0 mysql> select count(*) from t_user; +----------+ | count(*) | +----------+ | 5000000 | +----------+ 1 row in set (3.78 sec)
以下是实验的重点
还有以下测试情况不考虑联合索引
联合索引的情况复杂一点、下次再验证
1、我们先分析在没有索引的情况下。
mysql> select * from t_user where f_rangenum = 123568; +---------+----------------+---------------------+----------+------------+ | f_uin | f_name | f_createtime | f_status | f_rangenum | +---------+----------------+---------------------+----------+------------+ | 123569 | zhantao_123568 | 2015-04-18 20:11:36 | 1 | 123568 | | 1123569 | zhantao_123568 | 2015-04-18 20:11:54 | 1 | 123568 | | 2123569 | zhantao_123568 | 2015-04-18 20:12:05 | 1 | 123568 | | 3123569 | zhantao_123568 | 2015-04-18 20:12:15 | 1 | 123568 | | 4123569 | zhantao_123568 | 2015-04-18 20:12:25 | 1 | 123568 | +---------+----------------+---------------------+----------+------------+ 5 rows in set (2.19 sec) mysql> explain select * from t_user where f_rangenum = 123568; +----+-------------+--------+------+---------------+------+---------+------+---------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+---------------+------+---------+------+---------+-------------+ | 1 | SIMPLE | t_user | ALL | NULL | NULL | NULL | NULL | 4989899 | Using where | +----+-------------+--------+------+---------------+------+---------+------+---------+-------------+ 1 row in set (0.00 sec)
在没有索引的情况下执行了2秒多
explian sql语句 发现几乎它的type类型是All 即效率最差的
rows 为mysql认为需要查看的条数。 几乎是全表每条数据的扫了一边
效率极低
2、在f_rangenum上增加索引,分析sql语句
mysql> alter table t_user add index f_rangenum_index(f_rangenum); Query OK, 5000000 rows affected (1 min 45.16 sec) Records: 5000000 Duplicates: 0 Warnings: 0
数量量大了,添加索引很慢。。。。。。。。
mysql> select * from t_user where f_rangenum = 123199; +---------+----------------+---------------------+----------+------------+ | f_uin | f_name | f_createtime | f_status | f_rangenum | +---------+----------------+---------------------+----------+------------+ | 123200 | zhantao_123199 | 2015-04-18 20:11:36 | 1 | 123199 | | 1123200 | zhantao_123199 | 2015-04-18 20:11:54 | 1 | 123199 | | 2123200 | zhantao_123199 | 2015-04-18 20:12:05 | 1 | 123199 | | 3123200 | zhantao_123199 | 2015-04-18 20:12:15 | 1 | 123199 | | 4123200 | zhantao_123199 | 2015-04-18 20:12:25 | 1 | 123199 | +---------+----------------+---------------------+----------+------------+ 5 rows in set (0.02 sec) mysql> explain select * from t_user where f_rangenum = 123199; +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+ | 1 | SIMPLE | t_user | ref | f_rangenum_index | f_rangenum_index | 4 | const | 5 | | +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+ 1 row in set (0.00 sec)
在有索引的情况下 执行效率非常高
看explain rows为5 只查了五条数据
它的type为ref 表示 是根据key(f_rangenum_index )常数123199来查询的
所以效果很好
3、where后面的 过滤条件顺序是否有影响
mysql> select * from t_user where f_rangenum = 123199; +---------+-------------------------+---------------------+----------+------------+ | f_uin | f_name | f_createtime | f_status | f_rangenum | +---------+-------------------------+---------------------+----------+------------+ | 123200 | zhantao_123599001123200 | 2015-04-18 20:11:36 | 1 | 123199 | | 1123200 | zhantao_123599002 | 2015-04-18 20:11:54 | 1 | 123199 | | 2123200 | zhantao_123199 | 2015-04-18 20:12:05 | 1 | 123199 | | 3123200 | zhantao_123199 | 2015-04-18 20:12:15 | 1 | 123199 | | 4123200 | zhantao_123199 | 2015-04-18 20:12:25 | 1 | 123199 | +---------+-------------------------+---------------------+----------+------------+ 5 rows in set (0.00 sec) mysql> select * from t_user where f_rangenum = 123199 and f_name = "zhantao_123599001123200"; +--------+-------------------------+---------------------+----------+------------+ | f_uin | f_name | f_createtime | f_status | f_rangenum | +--------+-------------------------+---------------------+----------+------------+ | 123200 | zhantao_123599001123200 | 2015-04-18 20:11:36 | 1 | 123199 | +--------+-------------------------+---------------------+----------+------------+ 1 row in set (0.00 sec) mysql> select * from t_user where f_name = "zhantao_123599001123200" and f_rangenum = 123199; +--------+-------------------------+---------------------+----------+------------+ | f_uin | f_name | f_createtime | f_status | f_rangenum | +--------+-------------------------+---------------------+----------+------------+ | 123200 | zhantao_123599001123200 | 2015-04-18 20:11:36 | 1 | 123199 | +--------+-------------------------+---------------------+----------+------------+ 1 row in set (0.00 sec) mysql> explain select * from t_user where f_name = "zhantao_123599001123200" and f_rangenum = 123199; +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+ | 1 | SIMPLE | t_user | ref | f_rangenum_index | f_rangenum_index | 4 | const | 5 | Using where | +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from t_user where f_rangenum = 123199 and f_name = "zhantao_123599001123200"; +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+ | 1 | SIMPLE | t_user | ref | f_rangenum_index | f_rangenum_index | 4 | const | 5 | Using where | +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+ 1 row in set (0.00 sec)
select
*
from
t_user
where
f_name =
"zhantao_123599001123200"
and
f_rangenum = 123199;
select
*
from
t_user
where
f_rangenum = 123199
and
f_name =
"zhantao_123599001123200"
;
两个语句一样
只是把where后面的字段顺序挑换了一下
一个先写设置了索引的过滤条件,另一个先写没有过滤索引的字段
我们可以发现 它们执行的时间是一样的。
它们的explain的结果也一样
说明它们where后面的顺序不影响。
我想应该是mysql 的sql优化器 会去先执行有索引的字段然后再查找非索引的字段
4、关于where 1=1 是否会导致全变扫描
废话不多说 情况跟上面的一样
应该是mysql 的sql优化器会过滤掉1=1 所以根本不会导致全表扫描
mysql> explain select * from t_user where 1=1 and f_rangenum = 123199; +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+ | 1 | SIMPLE | t_user | ref | f_rangenum_index | f_rangenum_index | 4 | const | 5 | | +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+ 1 row in set (0.00 sec) mysql> explain select * from t_user where f_rangenum = 123199; +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+ | 1 | SIMPLE | t_user | ref | f_rangenum_index | f_rangenum_index | 4 | const | 5 | | +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+ 1 row in set (0.00 sec) mysql> select * from t_user where f_rangenum = 123199; +---------+-------------------------+---------------------+----------+------------+ | f_uin | f_name | f_createtime | f_status | f_rangenum | +---------+-------------------------+---------------------+----------+------------+ | 123200 | zhantao_123599001123200 | 2015-04-18 20:11:36 | 1 | 123199 | | 1123200 | zhantao_123599002 | 2015-04-18 20:11:54 | 1 | 123199 | | 2123200 | zhantao_123199 | 2015-04-18 20:12:05 | 1 | 123199 | | 3123200 | zhantao_123199 | 2015-04-18 20:12:15 | 1 | 123199 | | 4123200 | zhantao_123199 | 2015-04-18 20:12:25 | 1 | 123199 | +---------+-------------------------+---------------------+----------+------------+ 5 rows in set (0.00 sec) mysql> select * from t_user where 1=1 and f_rangenum = 123199; +---------+-------------------------+---------------------+----------+------------+ | f_uin | f_name | f_createtime | f_status | f_rangenum | +---------+-------------------------+---------------------+----------+------------+ | 123200 | zhantao_123599001123200 | 2015-04-18 20:11:36 | 1 | 123199 | | 1123200 | zhantao_123599002 | 2015-04-18 20:11:54 | 1 | 123199 | | 2123200 | zhantao_123199 | 2015-04-18 20:12:05 | 1 | 123199 | | 3123200 | zhantao_123199 | 2015-04-18 20:12:15 | 1 | 123199 | | 4123200 | zhantao_123199 | 2015-04-18 20:12:25 | 1 | 123199 | +---------+-------------------------+---------------------+----------+------------+ 5 rows in set (0.00 sec)
总结是无论where后面的索引在什么位置都会使用索引
mysql 组合索引
1、组合索引
1)添加组合索引
mysql> alter table t_user_bak add index f_namerangenum_index(f_name,f_rangenum); Query OK, 5000000 rows affected, 2 warnings (2 min 54.18 sec) Records: 5000000 Duplicates: 0 Warnings: 0 mysql> show create table t_user_bak\G; *************************** 1. row *************************** Table: t_user_bak Create Table: CREATE TABLE `t_user_bak` ( `f_uin` bigint(20) NOT NULL AUTO_INCREMENT, `f_name` varchar(256) NOT NULL DEFAULT ‘‘, `f_createtime` datetime NOT NULL DEFAULT ‘0000-00-00 00:00:00‘, `f_status` int(11) NOT NULL DEFAULT ‘0‘, `f_rangenum` int(11) NOT NULL DEFAULT ‘0‘, PRIMARY KEY (`f_uin`), KEY `f_namerangenum_index` (`f_name`(255),`f_rangenum`) ) ENGINE=InnoDB AUTO_INCREMENT=5000001 DEFAULT CHARSET=utf8 1 row in set (0.00 sec)
2)
对于组合索引
我们看到 只要是查询条件中有联合索引中最左边的那个索引字段
那么都会走索引
(3个或者多个联合索引 道理是一样的 )
mysql> explain select * from t_user_bak where f_rangenum= 155465 and f_name="zhantao_155465"; +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+ | 1 | SIMPLE | t_user_bak | ref | f_namerangenum_index | f_namerangenum_index | 771 | const,const | 5 | Using where | +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from t_user_bak where f_name="zhantao_155465" and f_rangenum= 155465; +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+ | 1 | SIMPLE | t_user_bak | ref | f_namerangenum_index | f_namerangenum_index | 771 | const,const | 5 | Using where | +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from t_user_bak where f_name="zhantao_155465" ; +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+ | 1 | SIMPLE | t_user_bak | ref | f_namerangenum_index | f_namerangenum_index | 767 | const | 5 | Using where | +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from t_user_bak where 1=1 and f_name="zhantao_155465" ; +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+ | 1 | SIMPLE | t_user_bak | ref | f_namerangenum_index | f_namerangenum_index | 767 | const | 5 | Using where | +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+ 1 row in set (0.00 sec) mysql> explain select * from t_user_bak where f_createtime = ‘2015-04-18 21:19:35‘ and f_name="zhantao_155465" ; +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+ | 1 | SIMPLE | t_user_bak | ref | f_namerangenum_index | f_namerangenum_index | 767 | const | 5 | Using where | +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+ 1 row in set (0.00 sec)
3) 各个查询条件下的速度
mysql> show create table t_user_bak\G; *************************** 1. row *************************** Table: t_user_bak Create Table: CREATE TABLE `t_user_bak` ( `f_uin` bigint(20) NOT NULL AUTO_INCREMENT, `f_name` varchar(256) NOT NULL DEFAULT ‘‘, `f_createtime` datetime NOT NULL DEFAULT ‘0000-00-00 00:00:00‘, `f_status` int(11) NOT NULL DEFAULT ‘0‘, `f_rangenum` int(11) NOT NULL DEFAULT ‘0‘, PRIMARY KEY (`f_uin`), KEY `f_namecreatetimerangenum_index` (`f_name`(255),`f_createtime`,`f_rangenum`) ) ENGINE=InnoDB AUTO_INCREMENT=5000001 DEFAULT CHARSET=utf8 1 row in set (0.00 sec) ERROR: No query specified mysql> show create table t_user\G; *************************** 1. row *************************** Table: t_user Create Table: CREATE TABLE `t_user` ( `f_uin` bigint(20) NOT NULL AUTO_INCREMENT, `f_name` varchar(256) NOT NULL DEFAULT ‘‘, `f_createtime` datetime NOT NULL DEFAULT ‘0000-00-00 00:00:00‘, `f_status` int(11) NOT NULL DEFAULT ‘0‘, `f_rangenum` int(11) NOT NULL DEFAULT ‘0‘, PRIMARY KEY (`f_uin`), KEY `f_name_index` (`f_name`(255)), KEY `f_rangenum_index` (`f_rangenum`) ) ENGINE=InnoDB AUTO_INCREMENT=6000001 DEFAULT CHARSET=utf8 1 row in set (0.00 sec)
如下图
可以看出来 如果如果是联合索引 只会在最左边的那个索引字段上显示 MUL
但是是单列索引 每个索引上都有 MUL
这也就可以明白为什么在使用联合索引的时候 一定要有最左边的那个索引字段
mysql> desc t_user_bak; +--------------+--------------+------+-----+---------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------------------+----------------+ | f_uin | bigint(20) | NO | PRI | NULL | auto_increment | | f_name | varchar(256) | NO | MUL | | | | f_createtime | datetime | NO | | 0000-00-00 00:00:00 | | | f_status | int(11) | NO | | 0 | | | f_rangenum | int(11) | NO | | 0 | | +--------------+--------------+------+-----+---------------------+----------------+ 5 rows in set (0.00 sec) mysql> desc t_user; +--------------+--------------+------+-----+---------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+--------------+------+-----+---------------------+----------------+ | f_uin | bigint(20) | NO | PRI | NULL | auto_increment | | f_name | varchar(256) | NO | MUL | | | | f_createtime | datetime | NO | | 0000-00-00 00:00:00 | | | f_status | int(11) | NO | | 0 | | | f_rangenum | int(11) | NO | MUL | 0 | | +--------------+--------------+------+-----+---------------------+----------------+ 5 rows in set (0.00 sec)
可以看到 单列索引 和 组合索引 查询效果都是差不多的 不知道为什么
对组合索引 和 在各个单列上建索引的区别
mysql> select * from t_user where 1=1 and f_name = "zhantao_155465" and f_status !=2 and f_rangenum= 155465 ; +---------+----------------+---------------------+----------+------------+ | f_uin | f_name | f_createtime | f_status | f_rangenum | +---------+----------------+---------------------+----------+------------+ | 155466 | zhantao_155465 | 2015-04-18 21:21:11 | 1 | 155465 | | 1155466 | zhantao_155465 | 2015-04-18 21:21:20 | 1 | 155465 | | 2155466 | zhantao_155465 | 2015-04-18 21:21:29 | 1 | 155465 | | 3155466 | zhantao_155465 | 2015-04-18 21:21:38 | 1 | 155465 | | 4155466 | zhantao_155465 | 2015-04-18 21:21:48 | 1 | 155465 | +---------+----------------+---------------------+----------+------------+ 5 rows in set (0.03 sec) mysql> select * from t_user_bak where 1=1 and f_name = "zhantao_155465" and f_status !=2 and f_rangenum= 155465 ; +---------+----------------+---------------------+----------+------------+ | f_uin | f_name | f_createtime | f_status | f_rangenum | +---------+----------------+---------------------+----------+------------+ | 155466 | zhantao_155465 | 2015-04-18 21:19:35 | 1 | 155465 | | 1155466 | zhantao_155465 | 2015-04-18 21:19:47 | 1 | 155465 | | 2155466 | zhantao_155465 | 2015-04-18 21:20:10 | 1 | 155465 | | 3155466 | zhantao_155465 | 2015-04-18 21:20:20 | 1 | 155465 | | 4155466 | zhantao_155465 | 2015-04-18 21:20:37 | 1 | 155465 | +---------+----------------+---------------------+----------+------------+ 5 rows in set (0.03 sec)
下面是从网上找的分析
感觉说的很有道理
给我的感觉就是联合索引 不用回表
有了上面这些数据,我们整理下吧。未存在缓存下的数据。
看这个表,全表扫描最慢,我们可以理解,同时主键查询比覆盖所有扫描慢也还能接受,但是为什么主键扫描会比非主键扫描慢?
而且非主键查询需要消耗的1次查询的io+一次回表的查询IO,理论上是要比主键扫描慢,而出来的数据缺不是如此。
那么就仔细看下是个查询方式在各个主要阶段消耗的时间吧。
查询是否存在缓存,打开表及锁表这些操作时间是差不多,我们不会计入。具体还是看init,optimizing等环节消耗的时间。
1.从这个表中,我们看到非主键索引和覆盖索引在准备时间上需要开销很多的时间,预估这两种查询方式都需要进行回表操作,所以花在准备上更多时间。
2.第二项optimizing上,可以清晰知道,覆盖索引话在优化上大量的时间,这样在二级索引上就无需回表。
3. Sendingdata,全表扫描慢就慢在这一项上,因为是加载所有的数据页,所以花费在这块上时间较大,其他三者都差不多。
4. 非主键查询话在freeingitems上时间最少,那么可以看出它在读取数据块的时候最少。
5.相比较主键查询和非主键查询,非主键查询在Init,statistics都远高于主键查询,只是在freeingitems开销时间比主键查询少。因为这里测试数据比较少,但是我们可以预见在大数据量的查询上,不走缓存的话,那么主键查询的速度是要快于非主键查询的,本次数据不过是太小体现不出差距而已。
6.在大多数情况下,全表扫描还是要慢于索引扫描的。
tips:
过程中的辅助命令:
1.清楚缓存
reset query cache ;
flush tables;
2.查看表的索引:
show
index
from
tablename;
mysql> set profiling=1; Query OK, 0 rows affected (0.00 sec) mysql> show profiles; +----------+------------+------------------------------------------------------------+ | Query_ID | Duration | Query | +----------+------------+------------------------------------------------------------+ | 1 | 0.00665000 | select * from t_user where f_rangenum in (1,2,3,4,5,6,7,8) | +----------+------------+------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> show profile for query 1; +--------------------+----------+ | Status | Duration | +--------------------+----------+ | starting | 0.000153 | | Opening tables | 0.000023 | | System lock | 0.000006 | | Table lock | 0.000012 | | init | 0.000084 | | optimizing | 0.000014 | | statistics | 0.001265 | | preparing | 0.000018 | | executing | 0.000004 | | Sending data | 0.003164 | | end | 0.000010 | | query end | 0.000004 | | freeing items | 0.001880 | | logging slow query | 0.000007 | | cleaning up | 0.000006 | +--------------------+----------+ 15 rows in set (0.00 sec)
最后关于mysql where in 是否启用索引
直接上explain结果 一目了然
mysql> explain select * from t_user where f_rangenum in (select f_id from t_globe_num); +----+--------------------+-------------+-----------------+---------------+---------+---------+------+---------+--------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+-------------+-----------------+---------------+---------+---------+------+---------+--------------------------+ | 1 | PRIMARY | t_user | ALL | NULL | NULL | NULL | NULL | 6001509 | Using where | | 2 | DEPENDENT SUBQUERY | t_globe_num | unique_subquery | PRIMARY | PRIMARY | 8 | func | 1 | Using index; Using where | +----+--------------------+-------------+-----------------+---------------+---------+---------+------+---------+--------------------------+ 2 rows in set (0.00 sec) mysql> explain select * from t_user where f_rangenum in (1,2,3,4,5,6); +----+-------------+--------+-------+------------------+------------------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+--------+-------+------------------+------------------+---------+------+------+-------------+ | 1 | SIMPLE | t_user | range | f_rangenum_index | f_rangenum_index | 4 | NULL | 36 | Using where | +----+-------------+--------+-------+------------------+------------------+---------+------+------+-------------+ 1 row in set (0.04 sec)
可以看到 如果in里面是值 那么会启用index
但是如果 是子句则不走index是全表扫描
t_user表600万个数据
t_globe_num 表1万个数据
rows 那里显示6001509 ~~~
mysql要查600多万条数据 卡死你~~~~