之前看了很多讲索引和优化的文章,自己也没咋用过。这里终于造了点数据。也来验证一下;
这里参考这篇文章https://blog.csdn.net/u012954706/article/details/81241049
第一部分
索引选取类型
- 越小的数据类型通常更好;越小的数据类型通常在磁盘、内存和CPU缓存中都需要更少的空间,处理起来更快。
- 简单的数据类型更好:整型数据比起字符串处理开销更小,因为字符串的比较更复杂。
- 尽量避免null,应该制定列为not null,在mysql中,含有空值的列很难进行查询优化,因为它们使得索引、索引的统计信息以及比较 运算更加复杂
不适合建立索引的场景
- 对于在那些查询中很少使用或者参考的列不应该创建索引。因为这些列很少用到,因此有索引或者无索引,并不能提高查询速度。相反由于增加了索引,反而降低了系统的维护速度和增大了空间需求;
- 只有很少的数据值的列比如性别
- 数据类型为 text,image,bit
- 修改性能大于检索性能时,不应该创建索引
- 不会出现在where条件中的字段不应该建立索引
适合建索引的字段
- 表的主键(默认索引)外键
- 数据量超过300的表应该建立索引
- 经常与其它表进行连接的表,在连接字段上应该建立索引
- 经常出现在where子句中的字段,加快判断速度,特别是大表的字段,应该建立索引
- 经常用到排序的列
- 经常用在范围内搜索的列上的索引
索引的优点
- 索引由数据库中一列或者多列组合而成,作用是提高对表中数据的查询速度
- 索引的优点是可以提高检索数据的速度
缺点
- 创建和维护索引需要消耗时间
- 会减慢写入速度
- 一个表的索引数最好不要超过6个
第二部分
1. SELECT 的时候,选择需要的列
SELECT * FROM user;
SELECT user_phone FORM user;
2. 主键是默认索引
-- id=1
SELECT * FROM `user` WHERE user_phone = '18756943707';
-- id=38w
SELECT * FROM `user` WHERE user_phone = '18697483918';
-- id=50w
SELECT * FROM `user` WHERE user_phone = '15089123074';
SELECT * FROM `user` WHERE user_id = 100000;
SELECT * FROM `user` WHERE user_id = 500000;
这里可以看见,主键查询的时间都差不多;
然后这里发现,不管手机号在哪查询时间都是一样的
关于limit 1
前面发现,手机号在哪个位置查询的时间都差不多,因为数据库并不知道有多少个符合条件的结果,所以进行了全表扫描
-- id=1
SELECT * FROM `user` WHERE user_phone = '18756943707' LIMIT 1;
SELECT * FROM `user` WHERE user_phone = '18756943707';
-- id=38w
SELECT * FROM `user` WHERE user_phone = '18697483918' LIMIT 1;
-- id=50w
SELECT * FROM `user` WHERE user_phone = '15089123074' LIMIT 1;
结果很明显,所以说,如果我们确定了数据只有一条,那么加一个limit 1
普通索引
SELECT * FROM `user` WHERE user_phone = '18756943707';
SELECT * FROM `user` WHERE user_id = 500000;
速度差不多,索引还是挺有用的
唯一索引
前面说普通索引不能有空值,我刚刚试了几个空值,感觉没啥影响啊,求解答
唯一索引允许一个空值
索引要求not null,解答2019-9-30
索引列
- 设置not null
- 不设置not null
区别:不设置not null索引的key_len会多1个字节.数据少还好,上亿条记录就是上亿个字节
查询null也不太方便
end
联合索引
- 需要加索引的字段,要在where中
- 数据量少的字段不需要加索引
- 如果where条件中是or关系,加索引不起作用
- 符合最左原则
最左原则
联合索引又称符合索引,如果索引的 key index(a, b, c);那么可以支持 a| a, b| a, b, c|三种组合进行查找,但不支持 b, c 进行查找
这里我来试试
--创建一个联合索引
CREATE INDEX test_union ON `user`(user_phone, user_name, user_age);
SELECT * FROM `user` WHERE user_phone = '18657322009';
SELECT * FROM `user` WHERE user_phone = '18047537377' AND user_name = '柳桃' AND user_age=34;
SELECT * FROM `user` WHERE user_name = '柳桃' AND user_age = 34 AND user_phone = '18047537378';
SELECT * FROM `user` WHERE user_phone = '18047537377' OR user_name = '柳桃';
SELECT * FROM `user` WHERE user_name = '李永以';
求解答
上面的回答:MySQL查询优化器 2019-9-28日
索引的概念和作用
- 索引是一种使记录有序化的技术,它可以指定按照某列/某几列预先排序,从而大大提高查询效率
- 索引的主要作用是加快数据查找,提高数据库性能
MySQL索引优化规则
- 前导模糊查询不能使用索引,非前导模糊查询则可以使用索引 例如
-- 这里我只给`name`建立了一个索引, `user_phone`没有建立索引
SELECT * FROM `user` WHERE user_name = '李永以';
SELECT * FROM `user` WHERE user_phone = '18047537377';
SELECT * FROM `user` WHERE user_name = '李%';
SELECT * FROM `user` WHERE user_name LIKE '%以';
SELECT * FROM `user` WHERE user_phone LIKE '18047537377';
查询结果如下
- union, in, or 都能命中索引,建议使用in
union能够命中索引,直接告诉MySQL怎么做,MySQL耗费的cpu最少,但一般不这么写SQL[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wa0MP99h-1573556576969)(http://blog.xukai.ink/wp-content/uploads/2019/09/BD61F6D884DB78A4AF489535FA76D945.gif)]网上说的,我也不知道是不是这样
SELECT * FROM `user` WHERE user_age = 4
UNION ALL
SELECT * FROM `user` WHERE user_age = 5;
in 能够命中索引,查询优化耗费的cpu比union all多,但是可以忽略不计,一般情况建议使用in
SELECT * FROM `user` WHERE user_age IN(4, 5);
or 新版的MySQL(具体我也不知道哪个是新版MySQL)能够命中索引,查询优化耗费的cup比in多,不建议频繁使用or
SELECT * FROM `user` WHERE user_age = 4 OR user_age = 5;
- 负向条件查询不能使用索引,可以优化为in查询
-- 负向查询条件有
!=,<>,NOI IN,NOT EXISTS,NOT LIKE 等
这一条,我也不太清楚
- 范围列可以用到索引
<、<= 、 >、 >=、 between等
根据我的测试,emmm,貌似是用到了索引
SELECT * FROM `user` WHERE user_age BETWEEN 10 AND 20; -- 加索引 0.215s;删掉索引 0.227s 我也不太清楚,我好难
- 把计算放到业务层,而不是数据库层(在字段上进行计算,不能命中索引)
SELECT * FROM `user` WHERE (2019 - user_age) > 2000;
SELECT * FROM `user` WHERE user_age < 18;
这个,emmmm
select * from order where deadline <= curdate();
-- 可以优化为
select * from order where deadline <= '2019-01-01 00:00:00';
传入的SQL相同,才可以利用查询缓存
- 强制类型转换,会全表扫描
select * FROM `user` WHERE user_phone = 15297450539;
select * FROM `user` WHERE user_phone = '15297450539';
8. 更新频繁,数据区分不高的字段不宜建立索引
- 更新会变更B+树,更新频繁的字段建立索引会大大降低数据库的性能
- ‘性别’这种区分度不大的属性,建立索引是没有什么意义的,不能有效过滤数据,性能与全表扫描类似
- 一般区分度在80%以上的时候可以建立索引,区分度可以用count(distinct(列名)) / count(*)来计算
SELECT count(DISTINCT(user_age)) / count(*) user_age,count(DISTINCT(user_id)) / count(*) user_id,count(DISTINCT(user_phone)) / count(*) user_phone FROM `user`;
结果:
user_age | user_id | user_phone |
---|---|---|
0.0002 | 1.0000 | 1.0000 |
原来是这个样子,我说上面的user_age怎么没啥用样的
今天先这么多了2019-9-23, 怎么一转眼就到了0点了,真快