由where 1 =1 引发的思考

最近工作上被说了

说代码中不能用 where 1=1,当时觉得是应该可以用的,但是找不到什么理据,
而且mysql 语句优化这方面确实很薄弱
 
感觉自己mysql方面是知识还是不够哇

得好好研究研究
还有发现 很多知识点 光看的话根本记不住,也不深刻。还是得亲手实践下
 
so  ~~~ 挫折越多进步越快
 

1、关于sql语句大小问题

1)mysql默认情况下没有设置 root用户密码

给mysql的root用户设置密码先
  1. [ztao@localhost ~]$ mysqladmin -uroot password "root"

2)默认情况下sql语句是限制在1M以内

  1. max_allowed_packet 表示sql最大为1M
  2. mysql> show VARIABLES like '%max_allowed_packet%';
  3. +--------------------------+------------+
  4. | Variable_name | Value |
  5. +--------------------------+------------+
  6. | max_allowed_packet | 1048576 |
  7. | slave_max_allowed_packet | 1073741824 |
  8. +--------------------------+------------+
  9. 2 rows in set (0.00 sec)

这里最好改大,如果太小的话sql语句超过1M会导致sql语句执行失败

3)

  1. [root@localhost ztao]# vim /etc/my.cnf
  2.  
  3. 添加红色的那一行
  4. [mysqld]
  5. datadir=/var/lib/mysql
  6. socket=/var/lib/mysql/mysql.sock
  7. user=mysql
  8. # Disabling symbolic-links is recommended to prevent assorted security risks
  9. symbolic-links=
  10. max_allowed_packet = 160M
  11. [mysqld_safe]
  12. log-error=/var/log/mysqld.log
  13. pid-file=/var/run/mysqld/mysqld.pid
4)
然后重启mysql 在查看下
160M = 160*1024*1024=167772160
  1. mysql> show VARIABLES like '%max_allowed_packet%';
  2. +--------------------------+------------+
  3. | Variable_name | Value |
  4. +--------------------------+------------+
  5. | max_allowed_packet | 167772160 |
  6. | slave_max_allowed_packet | 1073741824 |
  7. +--------------------------+------------+
  8. 2 rows in set (0.00 sec)

这样能支持你一条sql语句在160M以内

2、在window下写的脚本文件放在linux上执行失败

 
在Windows下写了一个shell脚本,

上传到Linux下执行时经常会报这种错误:

[root@localhost 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创建表
  1. #!/bin/sh
  2. dbenv=dev
  3.  
  4. if [ "${dbenv}" = "dev" ]; then
  5. mysql_user=root
  6. mysql_pass=root
  7. mysql_host=
  8. fi
  9. if [ "${dbenv}" = "idc" ]; then
  10. mysql_user=root
  11. mysql_pass=root
  12. mysql_host="-h 10.10.10.10"
  13. fi
  14.  
  15. mysql_cmd="mysql -u${mysql_user} -p${mysql_pass} ${mysql_host} --default-character-set=utf8"
  16.  
  17. ${mysql_cmd}<<EOF
  18. use test;
  19.  
  20. drop table if exists t_user;
  21. create table t_user
  22. (
  23. f_uin bigint() NOT NULL auto_increment,
  24. f_name varchar() NOT NULL DEFAULT '',
  25. f_createtime datetime not null default '0000-00-00 00:00:00',
  26. f_status int() NOT NULL DEFAULT '',
  27. f_rangenum int() NOT NULL DEFAULT '',
  28. PRIMARY KEY (f_uin)
  29. )ENGINE=InnoDB DEFAULT CHARSET=utf8;
  30. EOF
  31. echo "create table t_user ok"

2)通过python脚本来创建sql脚本

  1. #!/usr/bin/python
  2. #-*-coding:UTF-8-*-
  3.  
  4. import sys
  5.  
  6. def Insert(num):
  7.  
  8. if(num<=10000000):
  9. str = "insert into t_user (f_name,f_createtime,f_status,f_rangenum) values "
  10. for i in range(num):
  11. name = "zhantao_%d"%i
  12. status = 1
  13. rangenum = i
  14. if(i==0):
  15. strsql = "('%s',now(),%d,%d)"%(name,status,rangenum)
  16. else:
  17. strsql = ",('%s',now(),%d,%d)"%(name,status,rangenum)
  18. str += strsql
  19. f = open("insert.sql","w")
  20. f.write(str)
  21. f.close
  22.  
  23. if __name__ == '__main__':
  24. #num = int(sys.argv[1])
  25. 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
因为主键是自增的所以重复插入不会产生冲突
  1. mysql> use test
  2. Reading table information for completion of table and column names
  3. You can turn off this feature to get a quicker startup with -A
  4.  
  5. Database changed
  6. mysql> source /home/ztao/Work/Test/0418/insert.sql
  7. Query OK, 1000000 rows affected (11.77 sec)
  8. Records: 1000000 Duplicates: 0 Warnings: 0
  9.  
  10. mysql> source /home/ztao/Work/Test/0418/insert.sql
  11. Query OK, 1000000 rows affected (8.90 sec)
  12. Records: 1000000 Duplicates: 0 Warnings: 0
  13.  
  14. mysql> source /home/ztao/Work/Test/0418/insert.sql
  15. Query OK, 1000000 rows affected (8.43 sec)
  16. Records: 1000000 Duplicates: 0 Warnings: 0
  17.  
  18. mysql> source /home/ztao/Work/Test/0418/insert.sql
  19. Query OK, 1000000 rows affected (8.28 sec)
  20. Records: 1000000 Duplicates: 0 Warnings: 0
  21.  
  22. mysql> source /home/ztao/Work/Test/0418/insert.sql
  23. Query OK, 1000000 rows affected (7.87 sec)
  24. Records: 1000000 Duplicates: 0 Warnings: 0
  25.  
  26. mysql> select count(*) from t_user;
  27. +----------+
  28. | count(*) |
  29. +----------+
  30. | 5000000 |
  31. +----------+
  32. 1 row in set (3.78 sec)
以下是实验的重点
还有以下测试情况不考虑联合索引
联合索引的情况复杂一点、下次再验证
1、我们先分析在没有索引的情况下。
  1. mysql> select * from t_user where f_rangenum = 123568;
  2. +---------+----------------+---------------------+----------+------------+
  3. | f_uin | f_name | f_createtime | f_status | f_rangenum |
  4. +---------+----------------+---------------------+----------+------------+
  5. | 123569 | zhantao_123568 | 2015-04-18 20:11:36 | 1 | 123568 |
  6. | 1123569 | zhantao_123568 | 2015-04-18 20:11:54 | 1 | 123568 |
  7. | 2123569 | zhantao_123568 | 2015-04-18 20:12:05 | 1 | 123568 |
  8. | 3123569 | zhantao_123568 | 2015-04-18 20:12:15 | 1 | 123568 |
  9. | 4123569 | zhantao_123568 | 2015-04-18 20:12:25 | 1 | 123568 |
  10. +---------+----------------+---------------------+----------+------------+
  11. 5 rows in set (2.19 sec)
  12.  
  13. mysql> explain select * from t_user where f_rangenum = 123568;
  14. +----+-------------+--------+------+---------------+------+---------+------+---------+-------------+
  15. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  16. +----+-------------+--------+------+---------------+------+---------+------+---------+-------------+
  17. | 1 | SIMPLE | t_user | ALL | NULL | NULL | NULL | NULL | 4989899 | Using where |
  18. +----+-------------+--------+------+---------------+------+---------+------+---------+-------------+
  19. 1 row in set (0.00 sec)
在没有索引的情况下执行了2秒多
explian sql语句  发现几乎它的type类型是All  即效率最差的
rows 为mysql认为需要查看的条数。 几乎是全表每条数据的扫了一边
效率极低
 
2、在f_rangenum上增加索引,分析sql语句
  1. mysql> alter table t_user add index f_rangenum_index(f_rangenum);
  2. Query OK, 5000000 rows affected (1 min 45.16 sec)
  3. Records: 5000000 Duplicates: 0 Warnings: 0

数量量大了,添加索引很慢。。。。。。。。

  1. mysql> select * from t_user where f_rangenum = 123199;
  2. +---------+----------------+---------------------+----------+------------+
  3. | f_uin | f_name | f_createtime | f_status | f_rangenum |
  4. +---------+----------------+---------------------+----------+------------+
  5. | 123200 | zhantao_123199 | 2015-04-18 20:11:36 | 1 | 123199 |
  6. | 1123200 | zhantao_123199 | 2015-04-18 20:11:54 | 1 | 123199 |
  7. | 2123200 | zhantao_123199 | 2015-04-18 20:12:05 | 1 | 123199 |
  8. | 3123200 | zhantao_123199 | 2015-04-18 20:12:15 | 1 | 123199 |
  9. | 4123200 | zhantao_123199 | 2015-04-18 20:12:25 | 1 | 123199 |
  10. +---------+----------------+---------------------+----------+------------+
  11. 5 rows in set (0.02 sec)
  12.  
  13. mysql> explain select * from t_user where f_rangenum = 123199;
  14. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+
  15. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  16. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+
  17. | 1 | SIMPLE | t_user | ref | f_rangenum_index | f_rangenum_index | 4 | const | 5 | |
  18. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+
  19. 1 row in set (0.00 sec)
在有索引的情况下  执行效率非常高
看explain   rows为5   只查了五条数据
它的type为ref 表示 是根据key(f_rangenum_index )常数123199来查询的 
所以效果很好
 
3、where后面的  过滤条件顺序是否有影响
  1. mysql> select * from t_user where f_rangenum = 123199;
  2. +---------+-------------------------+---------------------+----------+------------+
  3. | f_uin | f_name | f_createtime | f_status | f_rangenum |
  4. +---------+-------------------------+---------------------+----------+------------+
  5. | 123200 | zhantao_123599001123200 | 2015-04-18 20:11:36 | 1 | 123199 |
  6. | 1123200 | zhantao_123599002 | 2015-04-18 20:11:54 | 1 | 123199 |
  7. | 2123200 | zhantao_123199 | 2015-04-18 20:12:05 | 1 | 123199 |
  8. | 3123200 | zhantao_123199 | 2015-04-18 20:12:15 | 1 | 123199 |
  9. | 4123200 | zhantao_123199 | 2015-04-18 20:12:25 | 1 | 123199 |
  10. +---------+-------------------------+---------------------+----------+------------+
  11. 5 rows in set (0.00 sec)
  12.  
  13. mysql> select * from t_user where f_rangenum = 123199 and f_name = "zhantao_123599001123200";
  14. +--------+-------------------------+---------------------+----------+------------+
  15. | f_uin | f_name | f_createtime | f_status | f_rangenum |
  16. +--------+-------------------------+---------------------+----------+------------+
  17. | 123200 | zhantao_123599001123200 | 2015-04-18 20:11:36 | 1 | 123199 |
  18. +--------+-------------------------+---------------------+----------+------------+
  19. 1 row in set (0.00 sec)
  20.  
  21. mysql> select * from t_user where f_name = "zhantao_123599001123200" and f_rangenum = 123199;
  22. +--------+-------------------------+---------------------+----------+------------+
  23. | f_uin | f_name | f_createtime | f_status | f_rangenum |
  24. +--------+-------------------------+---------------------+----------+------------+
  25. | 123200 | zhantao_123599001123200 | 2015-04-18 20:11:36 | 1 | 123199 |
  26. +--------+-------------------------+---------------------+----------+------------+
  27. 1 row in set (0.00 sec)
  28.  
  29. mysql> explain select * from t_user where f_name = "zhantao_123599001123200" and f_rangenum = 123199;
  30. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+
  31. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  32. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+
  33. | 1 | SIMPLE | t_user | ref | f_rangenum_index | f_rangenum_index | 4 | const | 5 | Using where |
  34. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+
  35. 1 row in set (0.00 sec)
  36.  
  37. mysql> explain select * from t_user where f_rangenum = 123199 and f_name = "zhantao_123599001123200";
  38. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+
  39. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  40. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+
  41. | 1 | SIMPLE | t_user | ref | f_rangenum_index | f_rangenum_index | 4 | const | 5 | Using where |
  42. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------------+
  43. 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  所以根本不会导致全表扫描
  1. mysql> explain select * from t_user where 1=1 and f_rangenum = 123199;
  2. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+
  3. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  4. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+
  5. | 1 | SIMPLE | t_user | ref | f_rangenum_index | f_rangenum_index | 4 | const | 5 | |
  6. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+
  7. 1 row in set (0.00 sec)
  8.  
  9. mysql> explain select * from t_user where f_rangenum = 123199;
  10. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+
  11. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  12. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+
  13. | 1 | SIMPLE | t_user | ref | f_rangenum_index | f_rangenum_index | 4 | const | 5 | |
  14. +----+-------------+--------+------+------------------+------------------+---------+-------+------+-------+
  15. 1 row in set (0.00 sec)
  16.  
  17. mysql> select * from t_user where f_rangenum = 123199;
  18. +---------+-------------------------+---------------------+----------+------------+
  19. | f_uin | f_name | f_createtime | f_status | f_rangenum |
  20. +---------+-------------------------+---------------------+----------+------------+
  21. | 123200 | zhantao_123599001123200 | 2015-04-18 20:11:36 | 1 | 123199 |
  22. | 1123200 | zhantao_123599002 | 2015-04-18 20:11:54 | 1 | 123199 |
  23. | 2123200 | zhantao_123199 | 2015-04-18 20:12:05 | 1 | 123199 |
  24. | 3123200 | zhantao_123199 | 2015-04-18 20:12:15 | 1 | 123199 |
  25. | 4123200 | zhantao_123199 | 2015-04-18 20:12:25 | 1 | 123199 |
  26. +---------+-------------------------+---------------------+----------+------------+
  27. 5 rows in set (0.00 sec)
  28.  
  29. mysql> select * from t_user where 1=1 and f_rangenum = 123199;
  30. +---------+-------------------------+---------------------+----------+------------+
  31. | f_uin | f_name | f_createtime | f_status | f_rangenum |
  32. +---------+-------------------------+---------------------+----------+------------+
  33. | 123200 | zhantao_123599001123200 | 2015-04-18 20:11:36 | 1 | 123199 |
  34. | 1123200 | zhantao_123599002 | 2015-04-18 20:11:54 | 1 | 123199 |
  35. | 2123200 | zhantao_123199 | 2015-04-18 20:12:05 | 1 | 123199 |
  36. | 3123200 | zhantao_123199 | 2015-04-18 20:12:15 | 1 | 123199 |
  37. | 4123200 | zhantao_123199 | 2015-04-18 20:12:25 | 1 | 123199 |
  38. +---------+-------------------------+---------------------+----------+------------+
  39. 5 rows in set (0.00 sec)

总结是无论where后面的索引在什么位置都会使用索引

mysql 组合索引

1、组合索引
1)添加组合索引
  1. mysql> alter table t_user_bak add index f_namerangenum_index(f_name,f_rangenum);
  2. Query OK, 5000000 rows affected, 2 warnings (2 min 54.18 sec)
  3. Records: 5000000 Duplicates: 0 Warnings: 0
  4.  
  5. mysql> show create table t_user_bak\G;
  6. *************************** 1. row ***************************
  7. Table: t_user_bak
  8. Create Table: CREATE TABLE `t_user_bak` (
  9. `f_uin` bigint(20) NOT NULL AUTO_INCREMENT,
  10. `f_name` varchar(256) NOT NULL DEFAULT '',
  11. `f_createtime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  12. `f_status` int(11) NOT NULL DEFAULT '',
  13. `f_rangenum` int(11) NOT NULL DEFAULT '',
  14. PRIMARY KEY (`f_uin`),
  15. KEY `f_namerangenum_index` (`f_name`(255),`f_rangenum`)
  16. ) ENGINE=InnoDB AUTO_INCREMENT=5000001 DEFAULT CHARSET=utf8
  17. 1 row in set (0.00 sec)
2)
对于组合索引
我们看到 只要是查询条件中有联合索引中最左边的那个索引字段
那么都会走索引
(3个或者多个联合索引  道理是一样的 )
  1. mysql> explain select * from t_user_bak where f_rangenum= 155465 and f_name="zhantao_155465";
  2. +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+
  3. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  4. +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+
  5. | 1 | SIMPLE | t_user_bak | ref | f_namerangenum_index | f_namerangenum_index | 771 | const,const | 5 | Using where |
  6. +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+
  7. 1 row in set (0.00 sec)
  8.  
  9. mysql> explain select * from t_user_bak where f_name="zhantao_155465" and f_rangenum= 155465;
  10. +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+
  11. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  12. +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+
  13. | 1 | SIMPLE | t_user_bak | ref | f_namerangenum_index | f_namerangenum_index | 771 | const,const | 5 | Using where |
  14. +----+-------------+------------+------+----------------------+----------------------+---------+-------------+------+-------------+
  15. 1 row in set (0.00 sec
  16.  
  17. mysql> explain select * from t_user_bak where f_name="zhantao_155465" ;
  18. +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+
  19. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  20. +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+
  21. | 1 | SIMPLE | t_user_bak | ref | f_namerangenum_index | f_namerangenum_index | 767 | const | 5 | Using where |
  22. +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+
  23. 1 row in set (0.00 sec)
  24.  
  25. mysql> explain select * from t_user_bak where 1=1 and f_name="zhantao_155465" ;
  26. +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+
  27. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  28. +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+
  29. | 1 | SIMPLE | t_user_bak | ref | f_namerangenum_index | f_namerangenum_index | 767 | const | 5 | Using where |
  30. +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+
  31. 1 row in set (0.00 sec)
  32.  
  33. mysql> explain select * from t_user_bak where f_createtime = '2015-04-18 21:19:35' and f_name="zhantao_155465" ;
  34. +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+
  35. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  36. +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+
  37. | 1 | SIMPLE | t_user_bak | ref | f_namerangenum_index | f_namerangenum_index | 767 | const | 5 | Using where |
  38. +----+-------------+------------+------+----------------------+----------------------+---------+-------+------+-------------+
  39. 1 row in set (0.00 sec)

3) 各个查询条件下的速度

  1. mysql> show create table t_user_bak\G;
  2. *************************** 1. row ***************************
  3. Table: t_user_bak
  4. Create Table: CREATE TABLE `t_user_bak` (
  5. `f_uin` bigint(20) NOT NULL AUTO_INCREMENT,
  6. `f_name` varchar(256) NOT NULL DEFAULT '',
  7. `f_createtime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  8. `f_status` int(11) NOT NULL DEFAULT '',
  9. `f_rangenum` int(11) NOT NULL DEFAULT '',
  10. PRIMARY KEY (`f_uin`),
  11. KEY `f_namecreatetimerangenum_index` (`f_name`(255),`f_createtime`,`f_rangenum`)
  12. ) ENGINE=InnoDB AUTO_INCREMENT=5000001 DEFAULT CHARSET=utf8
  13. 1 row in set (0.00 sec)
  14.  
  15. ERROR:
  16. No query specified
  17.  
  18. mysql> show create table t_user\G;
  19. *************************** 1. row ***************************
  20. Table: t_user
  21. Create Table: CREATE TABLE `t_user` (
  22. `f_uin` bigint(20) NOT NULL AUTO_INCREMENT,
  23. `f_name` varchar(256) NOT NULL DEFAULT '',
  24. `f_createtime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  25. `f_status` int(11) NOT NULL DEFAULT '',
  26. `f_rangenum` int(11) NOT NULL DEFAULT '',
  27. PRIMARY KEY (`f_uin`),
  28. KEY `f_name_index` (`f_name`(255)),
  29. KEY `f_rangenum_index` (`f_rangenum`)
  30. ) ENGINE=InnoDB AUTO_INCREMENT=6000001 DEFAULT CHARSET=utf8
  31. 1 row in set (0.00 sec)
如下图
可以看出来  如果如果是联合索引  只会在最左边的那个索引字段上显示 MUL
但是是单列索引  每个索引上都有 MUL
这也就可以明白为什么在使用联合索引的时候 一定要有最左边的那个索引字段
  1. mysql> desc t_user_bak;
  2. +--------------+--------------+------+-----+---------------------+----------------+
  3. | Field | Type | Null | Key | Default | Extra |
  4. +--------------+--------------+------+-----+---------------------+----------------+
  5. | f_uin | bigint(20) | NO | PRI | NULL | auto_increment |
  6. | f_name | varchar(256) | NO | MUL | | |
  7. | f_createtime | datetime | NO | | 0000-00-00 00:00:00 | |
  8. | f_status | int(11) | NO | | 0 | |
  9. | f_rangenum | int(11) | NO | | 0 | |
  10. +--------------+--------------+------+-----+---------------------+----------------+
  11. 5 rows in set (0.00 sec)
  12.  
  13. mysql> desc t_user;
  14. +--------------+--------------+------+-----+---------------------+----------------+
  15. | Field | Type | Null | Key | Default | Extra |
  16. +--------------+--------------+------+-----+---------------------+----------------+
  17. | f_uin | bigint(20) | NO | PRI | NULL | auto_increment |
  18. | f_name | varchar(256) | NO | MUL | | |
  19. | f_createtime | datetime | NO | | 0000-00-00 00:00:00 | |
  20. | f_status | int(11) | NO | | 0 | |
  21. | f_rangenum | int(11) | NO | MUL | 0 | |
  22. +--------------+--------------+------+-----+---------------------+----------------+
  23. 5 rows in set (0.00 sec)
可以看到 单列索引 和 组合索引  查询效果都是差不多的  不知道为什么
对组合索引  和 在各个单列上建索引的区别
  1. mysql> select * from t_user where 1=1 and f_name = "zhantao_155465" and f_status !=2 and f_rangenum= 155465 ;
  2. +---------+----------------+---------------------+----------+------------+
  3. | f_uin | f_name | f_createtime | f_status | f_rangenum |
  4. +---------+----------------+---------------------+----------+------------+
  5. | 155466 | zhantao_155465 | 2015-04-18 21:21:11 | 1 | 155465 |
  6. | 1155466 | zhantao_155465 | 2015-04-18 21:21:20 | 1 | 155465 |
  7. | 2155466 | zhantao_155465 | 2015-04-18 21:21:29 | 1 | 155465 |
  8. | 3155466 | zhantao_155465 | 2015-04-18 21:21:38 | 1 | 155465 |
  9. | 4155466 | zhantao_155465 | 2015-04-18 21:21:48 | 1 | 155465 |
  10. +---------+----------------+---------------------+----------+------------+
  11. 5 rows in set (0.03 sec)
  12.  
  13. mysql> select * from t_user_bak where 1=1 and f_name = "zhantao_155465" and f_status !=2 and f_rangenum= 155465 ;
  14. +---------+----------------+---------------------+----------+------------+
  15. | f_uin | f_name | f_createtime | f_status | f_rangenum |
  16. +---------+----------------+---------------------+----------+------------+
  17. | 155466 | zhantao_155465 | 2015-04-18 21:19:35 | 1 | 155465 |
  18. | 1155466 | zhantao_155465 | 2015-04-18 21:19:47 | 1 | 155465 |
  19. | 2155466 | zhantao_155465 | 2015-04-18 21:20:10 | 1 | 155465 |
  20. | 3155466 | zhantao_155465 | 2015-04-18 21:20:20 | 1 | 155465 |
  21. | 4155466 | zhantao_155465 | 2015-04-18 21:20:37 | 1 | 155465 |
  22. +---------+----------------+---------------------+----------+------------+
  23. 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;
 
  1. mysql> set profiling=1;
  2. Query OK, 0 rows affected (0.00 sec)
  3.  
  4. mysql> show profiles;
  5. +----------+------------+------------------------------------------------------------+
  6. | Query_ID | Duration | Query |
  7. +----------+------------+------------------------------------------------------------+
  8. | 1 | 0.00665000 | select * from t_user where f_rangenum in (1,2,3,4,5,6,7,8) |
  9. +----------+------------+------------------------------------------------------------+
  10. 1 row in set (0.00 sec)
  11.  
  12. mysql> show profile for query 1;
  13. +--------------------+----------+
  14. | Status | Duration |
  15. +--------------------+----------+
  16. | starting | 0.000153 |
  17. | Opening tables | 0.000023 |
  18. | System lock | 0.000006 |
  19. | Table lock | 0.000012 |
  20. | init | 0.000084 |
  21. | optimizing | 0.000014 |
  22. | statistics | 0.001265 |
  23. | preparing | 0.000018 |
  24. | executing | 0.000004 |
  25. | Sending data | 0.003164 |
  26. | end | 0.000010 |
  27. | query end | 0.000004 |
  28. | freeing items | 0.001880 |
  29. | logging slow query | 0.000007 |
  30. | cleaning up | 0.000006 |
  31. +--------------------+----------+
  32. 15 rows in set (0.00 sec)
最后关于mysql  where in 是否启用索引
直接上explain结果 一目了然
  1. mysql> explain select * from t_user where f_rangenum in (select f_id from t_globe_num);
  2. +----+--------------------+-------------+-----------------+---------------+---------+---------+------+---------+--------------------------+
  3. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  4. +----+--------------------+-------------+-----------------+---------------+---------+---------+------+---------+--------------------------+
  5. | 1 | PRIMARY | t_user | ALL | NULL | NULL | NULL | NULL | 6001509 | Using where |
  6. | 2 | DEPENDENT SUBQUERY | t_globe_num | unique_subquery | PRIMARY | PRIMARY | 8 | func | 1 | Using index; Using where |
  7. +----+--------------------+-------------+-----------------+---------------+---------+---------+------+---------+--------------------------+
  8. 2 rows in set (0.00 sec)
  9.  
  10. mysql> explain select * from t_user where f_rangenum in (1,2,3,4,5,6);
  11. +----+-------------+--------+-------+------------------+------------------+---------+------+------+-------------+
  12. | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
  13. +----+-------------+--------+-------+------------------+------------------+---------+------+------+-------------+
  14. | 1 | SIMPLE | t_user | range | f_rangenum_index | f_rangenum_index | 4 | NULL | 36 | Using where |
  15. +----+-------------+--------+-------+------------------+------------------+---------+------+------+-------------+
  16. 1 row in set (0.04 sec)
可以看到 如果in里面是值  那么会启用index
但是如果 是子句则不走index是全表扫描
 
t_user表600万个数据
t_globe_num 表1万个数据
rows 那里显示6001509 ~~~
mysql要查600多万条数据 卡死你~~~~
 

mysql 索引相关知识的更多相关文章

  1. MongoDB 索引相关知识

    背景: MongoDB和MySQL一样,都会产生慢查询,所以都需要对其进行优化:包括创建索引.重构查询等.现在就说明在MongoDB下的索引相关知识点,可以通过这篇文章MongoDB 查询优化分析了解 ...

  2. mysql 索引相关

    引言: MYSQL由于其免费和开源的性质,在项目中用处广泛.大家都知道,一个MySQL数据库能够储存大量的数据,如果要在大量的数据中查找某一个数据,如果使用全表检索的话,即费时间又费力气,这时,就需要 ...

  3. mysql数据库相关知识

    什么是数据库?                数据库(Database)是按照数据结构来组织.存储和管理数据的建立在计算机存储设备上的仓库.(来自:百度) 什么是sql? 结构化查询语言(Struct ...

  4. 数据库(mysql)相关知识

      单表查询   排序   升序   select*from表名 order by字段 asc;   降序   select*from表名 order by字段 desc;   条件查询(包括通配符) ...

  5. MySQL 索引的知识整理

    前言:       很多面试者,在面试的时候,都会回答,”索引就相当于一本书的字典,有了他能够很快的找到数据”, 这种答案好像在读书的时候老师告诉这么说的吧.今天来全面的描述一下数据库索引的原理及优化 ...

  6. 面试小知识:MySQL索引相关

    前言 本模板主要是一些面试相关的题目,对于每一道问题,我会提供简单的解答,答案的来源主要是基于自己看了各方资料之后的理解,如果有错的,欢迎指点出来. 1. 什么是最左前缀原则? 以下回答全部是基于My ...

  7. mysql索引相关

    索引有主键索引.唯一索引.普通索引 单列索引,复合索引. 复合索引(a,b,c),可以理解是有三个索引,分别是a.b.c三个索引 前缀不是a的话,复合索引都不起作用,前缀用函数或者是范围,比如< ...

  8. mysql 索引相关问题

    mysql中key .primary key .unique key 与index区别 https://blog.csdn.net/nanamasuda/article/details/5254317 ...

  9. mysql索引相关理解

    1.索引是高效获取数据的数据结构, 2.唯一索引,索引值不重复unique create unique index 索引名 on 表名(字段) alter table 表名 add unique in ...

随机推荐

  1. [Angular 2] Rendering an Observable with the Async Pipe

    Angular 2 templates use a special Async pipe to be able to render out Observables. This lesson cover ...

  2. Meth | ubuntu下安装与卸载软件方法

    1.通过deb包安装的情况: 安装.deb包: 代码:sudo dpkg -i package_file.deb反安装.deb包:代码:sudo dpkg -r package_name 2.通过ap ...

  3. Bitmap基本概念及在Android4.4系统上使用BitmapFactory的注意事项

    本文首先总结一下Bitmap的相关概念,然后通过一个实际的问题来分析设置BitmapFactory.options的注意事项,以减少不必要的内存占用率,避免发生OOM. 一. Bitmap的使用tri ...

  4. RPM包校验和提取

    一.RPM包校验 [root@localhost Packages]# rpm -V 已安装的包名 #选项: #    -V    校验指定RPM包中的文件(verify) [root@localho ...

  5. JSON 格式化为易读格式的字符串

    算法 http://blog.csdn.net/yanghaitaohhh/article/details/39672783 使用算法如下: 对输入字符串,逐个字符的遍历 1.获取当前字符. 2.如果 ...

  6. mysql02

    -- 查询课程名称 和年级的名称 -- 非等值连接查询 SELECT subjectname,gradeName FROM `subject`,grade -- 等值连接查询 SELECT subje ...

  7. div中实现居中

    今天纠结了大半天的居中,把学到的先记录下来,还没完全弄清楚,发现网上原创的技术贴并不算多,大多都是相互转载.(ps.先安利一个大神的帖集,昨天才发现的,内容丰富,语言,呃...很幽默,一般都是图文并茂 ...

  8. LayoutInflater.inflate() 参数研究

    参考连接:http://blog.csdn.net/lovexieyuan520/article/details/9036673 http://www.2cto.com/kf/201407/31305 ...

  9. iOS判断UIScrollView的滚动方向

    - (void) scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat newY = scrollView.contentOffset.y; ...

  10. 关于JavaScript对象的键和值

    一个JavaScript对象由键和值组成. 当一个给定键的值被设置为一个字符串.布尔值.数字.数组或对象时,我们把这个键称为属性. 当把键设置为函数时,我们把它叫做方法.