mysql 索引相关知识

由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多万条数据 卡死你~~~~

时间: 2024-08-11 04:22:43

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

MySQL索引相关知识

MySQl索引创建 一.什么是索引? 索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录.表里面的记录数量越多,这个操作的代价就越高.如果作为搜索条件的列上已经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的位置.如果表有1000个记录,通过索引查找记录至少要比顺序扫描记录快100倍. 假设我们创建了一个名为people的表: CREATE TABLE

mysql 索引相关

引言: MYSQL由于其免费和开源的性质,在项目中用处广泛.大家都知道,一个MySQL数据库能够储存大量的数据,如果要在大量的数据中查找某一个数据,如果使用全表检索的话,即费时间又费力气,这时,就需要一种手段来减少这种消耗,这时候,索引就出现了!这里就简要介绍一下MYSQL的索引相关的内容. 索引是啥球东西: 索引的作用就像是相当于图书的目录,可以根据目录中的页码快速找到所需的内容.当表中有大量记录时,若要对表进行查询,第一种搜索方式是全表搜索,将所有记录一一取出,和查询条件进行一一对比,然后返

索引相关知识

索引 为什么使用索引 ? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,在生产环境中,我们遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,因此对查询语句的优化显然是重中之重.说起加速查询,就不得不提到索引了. ? 索引的目的在于提高查询效率,与我们查阅图书所用的目录是一个道理:先定位到章,然后定位到该章下的一个小节,然后找到页数.相似的例子还有:查字典,查火车车次,飞机航班等,下面内容看不懂的同学也没关系,能明白这个目录的道理就行了. 那么你想,书

MongoDB 索引相关知识

背景: MongoDB和MySQL一样,都会产生慢查询,所以都需要对其进行优化:包括创建索引.重构查询等.现在就说明在MongoDB下的索引相关知识点,可以通过这篇文章MongoDB 查询优化分析了解MongoDB慢查询的一些特点. 执行计划分析: 因为MongoDB也是BTree索引,所以使用上和MySQL大致一样.通过explain查看一个query的执行计划,来判断如何加索引,explain在3.0版本的时候做了一些改进,现在针对这2个版本进行分析: 3.0之前: zjy:PRIMARY>

mysql数据库相关知识

什么是数据库?                数据库(Database)是按照数据结构来组织.存储和管理数据的建立在计算机存储设备上的仓库.(来自:百度) 什么是sql? 结构化查询语言(Structured Query Language)简称SQL(发音:/?es kju? ?el/ "S-Q-L"),是一种特殊目的的编程语言,是一种数据库查询和程序设计语言,用于存取数据以及查询.更新和管理关系数据库系统:同时也是数据库脚本文件的扩展名.(来自:百度) RDBMS即关系数据库管理系统

mysql索引相关

1.mysql中,inner join 和 left join需要优化右表,而 right join 需要优化左表. 2.常用索引: 主键.排序.范围.where子句中 不用索引: 大数据类型,比如text.image.bit like字段后边 3.创建索引: alter table 表名  add index 索引名(列1,列2,列3....); 删除索引: drop index x on 表名; 查看索引: show index from 表名\G 4.索引失效 隐式转换(如果列类型为字符串

mysql SQL相关知识

1.insert insert into <表名>(字段名) values (值) 例: create table test ( id int(4) not null auto_increment, name char(20) not null, primary key(id) ) ; 1)按列名插入 2)不指定列名,则需按顺序插入 3)支持批量插入(可作为研发优化点) 4)删除数据 2.备份数据库 dump把数据库操作以SQL语句保存下来,逻辑备份 3.select(研发优化,最好不用*)

MYSQL数据库相关知识合集

1  MYSQL取得某一范围随机数: 关键词:RAND() [产生0~1之间的随机数] mysql> SELECT RAND( ), RAND( ), RAND( ); +------------------+-----------------+------------------+ | RAND( ) | RAND( ) | RAND( ) | +------------------+-----------------+------------------+ | 0.4546458492564

MySQL启动相关知识

使用mysqld和mysqld_safe启动的区别 直接运行mysqld程序来启动MySQL服务的方法很少见,mysqld_safe脚本[注意:mysqld_safe只是一个脚本]会在启动MySQL服务器后继续监控其运行情况,并在其死机时重新启动它.用mysqld_safe脚本来启动MySQL服务器的做法在BSD风格的unix系统上很常见,非BSD风格的UNIX系统中的 mysql.server脚本其实也是调用mysqld_safe脚本去启动MySQL服务器的.它通常做如下事情:1. 检查系统和