建表并插入数据
CREATE TABLE `dept` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`deptName` VARCHAR(30) DEFAULT NULL,
`address` VARCHAR(40) DEFAULT NULL,
ceo INT NULL , PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `emp` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`empno` INT NOT NULL ,
`name` VARCHAR(20) DEFAULT NULL,
`age` INT(3) DEFAULT NULL,
`deptId` INT(11) DEFAULT NULL,
PRIMARY KEY (`id`)
#CONSTRAINT `fk_dept_id` FOREIGN KEY (`deptId`) REFERENCES `t_dept` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
执行以下SQL语句
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=4 AND emp.name = 'abcd';
以上语句执行情况如下所示:
mysql> explain select SQL_NO_CACHE * from emp where age=30;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 500493 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set
mysql> explain select SQL_NO_CACHE * from emp where age=30 and deptid=4;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 500493 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set
mysql> explain select SQL_NO_CACHE * from emp where age=30 and deptid=4 and name='abcd';
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | emp | ALL | NULL | NULL | NULL | NULL | 500493 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set
建立索引
CREATE INDEX idx_age_deptid_name ON emp(age,deptid,NAME);
再次执行上述SQL语句
mysql> explain select SQL_NO_CACHE * from emp where age=30;
+----+-------------+-------+------+---------------------+---------------------+---------+-------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------------+---------------------+---------+-------+-------+-------------+
| 1 | SIMPLE | emp | ref | idx_name_deptid_age | idx_name_deptid_age | 5 | const | 47248 | Using where |
+----+-------------+-------+------+---------------------+---------------------+---------+-------+-------+-------------+
1 row in set
mysql> explain select SQL_NO_CACHE * from emp where age=30 and deptid=4;
+----+-------------+-------+------+---------------------+---------------------+---------+-------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------------+---------------------+---------+-------------+------+-------------+
| 1 | SIMPLE | emp | ref | idx_name_deptid_age | idx_name_deptid_age | 10 | const,const | 5 | Using where |
+----+-------------+-------+------+---------------------+---------------------+---------+-------------+------+-------------+
1 row in set
mysql> explain select SQL_NO_CACHE * from emp where age=30 and deptid=4 and name='abcd';
+----+-------------+-------+------+---------------------+---------------------+---------+-------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------------+---------------------+---------+-------------------+------+-------------+
| 1 | SIMPLE | emp | ref | idx_name_deptid_age | idx_name_deptid_age | 73 | const,const,const | 1 | Using where |
+----+-------------+-------+------+---------------------+---------------------+---------+-------------------+------+-------------+
1 row in set
mysql>
结论:全值匹配我最爱指的是,查询的字段按照顺序在索引中都可以匹配到。
SQL中查询字段的顺序,跟使用索引中字段的顺序,没有关系。优化器会在不影响SQL执行结果的前提下,进行自动优化。
查询字段与索引字段顺序的不同会导致,索引无法充分使用,甚至索引失效。
原因:使用复合索引,需要遵循最佳左前缀法则,即如果索引包含多列,要遵守最左前缀法则,指的是查询从索引的最左前列开始并不跳过索引中的列
**结论:**过滤条件要使用索引必须按照索引建立时的顺序,依次满足,一旦跳过某个字段,索引后面的字段都无法被使用。
不在索引列上做任何操作(计算、函数(自动or手动)类型转换),会导致索引失效而转向全表扫描。
执行以下SQL语句
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE age=30;
EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE LEFT(age,3)=30;
结论:等号左边无计算
首先建立索引,执行以下SQL语句
CREATE INDEX idx_name onemp(name);
explain select sql_no_cache * from emp where name='30000';
explain select sql_no_cache * from emp where name=30000;
字符串不加单引号,则会在name列上做一次转换。
结论:等号右边无转换!
explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid=5 AND emp.name = 'abcd';
explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptid<=5 AND emp.name = 'abcd';
建议:将可能做范围查询的字段的索引顺序放在最后。
即查询列和索引列一致,不要写select *
!
explain SELECT SQL_NO_CACHE * FROM emp WHERE emp.age=30 and deptId=4 and name='XamgXt';
explain SELECT SQL_NO_CACHE age,deptId,name FROM emp WHERE emp.age=30 and deptId=4 and name='XamgXt';
MySQL在使用不等于(!=或者<>)时,有时无法使用索引会导致全表扫描。
当字段允许为NULL的条件时:
结论:is not null用不到索引,is null可以用到索引
结论:前缀不能出现模糊匹配!
使用union all或者union来替代:
union和union all的区别
UNION去重且排序;UNION ALL不去重不排序
假设建立索引index(a,b,c)
Where语句 | 索引是否被使用 |
---|---|
where a = 3 | Y,使用到a |
where a = 3 and b=5 | Y,使用到a,b |
where a = 3 and b=5 and c=4 | Y,使用到a,b,c |
where b=3或者where b=3 and c=4 或者 where c=5 |
N |
where a=3 and c=5 | 使用到a,但是c不可以,b中间断了 |
where a=3 and b>4 and c =5 | 使用到a,b c不能用在范围之后,b断了 |
where a is null and b is not null | is null支持索引,但是is not null不支持,所以a可以使用索引,b不可以使用 |
where a <> 3 | 不能使用索引 |
where abs(a) = 3 | 不能使用索引 |
where a = 3 and b like ‘kk%’ and c=5 | Y,使用到a,b,c |
where a = 3 and b like ‘%kk’ and c=5 | Y,只用到a |
where a = 3 and b like ‘%kk%’ and c=5 | Y,只用到a |
where a = 3 and b like ‘k%k%’ and c=5 | Y,使用到a,b,c |