sql的索引设计和表优化都是非常重要的点,好的sql可以极大的减低成本,提高用户体验,而一条不好的sql就有可能让CPU100%,下面列举了一些常写的sql注意事项。
一、少用join之类联表查询
1,当数据量增加的时候,join会导致查询性能下降
2,分布式数据,分表分库比较多,join跨库性能表现不佳
3,join连接多个表,当一个表改动的时候,改动起来不方便
二、一些用不到索引的查询
1.负向查询一般用不到索引
select * from name != 'XXX';
2.强制类型转换用不到索引
select * from phone = 18999999999
phone是string类型,如果查询的时候没有加双引号,那么会导致全表烧苗,使用不到索引
3.复合索引左前缀
复合索引(uid,name)
select * from uid = 1 and name = 'xxx'; //使用到索引
select * from name = 'xxx' //没有使用索引
select * from name = 'xxx' and uid = 1 //使用到索引
4.null查询
索引不存null的值,所以值为null是无法使用索引的
select * from name is null; // 无法使用索引
5.前导模糊查询无法使用索引
select * from name like '%XX'; // 无法使用索引
三、优化查询
sql语句的优化,与之相关的东西说多不多,说少不少,其中非常重要的一点就是索引的运用。
对于索引,也许我们要从索引的原理和结构讲起,讲到B+tree,hash等,讲到这些估计又要科普一下
时间复杂度(O),讲到复杂度,又要从操作数来讲了,所以这里就不讲那么多,只讲基本的原理。
(1) 磁盘IO
一个数据库必须保证数据能随机随时读取,我们如果需要优化读取速率必须要明白数据是如何流动的。
这就涉及到磁盘IO了。
从数据库里面到数据的显示,并不是直接从数据库里面把数据拿到页面上的,而是需要经历一系列过
程。
现在讲一下计算机的运行原理:计算机运行自然是非常复杂的,但是其过程可以简单的介绍一下。
数据通过IO桥从磁盘里刷到主存中,在从主存中刷到寄存器中,最后在处理器中执行。
mysql在执行的过程中,会先从mysql的缓冲区中读取,如果缓冲区读取不到的话就会尝试从内存中加
载数据页,如果内存中也无法读取成功的话,就会尝试随机IO从磁盘中读取数据。
(2) 索引的设计
索引的设计没有想象中的难,只需掌握规律,设计一个不错的索引还是可行的。
磁盘IO中讲到了,数据的流动方向,每一层需要消耗的时间成本也是不同,数据缓存取数据,
速度非常快。而在磁盘中进行IO的话,需要付出很大的时间成本,但是如果数据是顺序读取的话
速度可以达到磁盘随机读取的几千,上万倍。
过滤因子
什么是过滤因子:
过滤因子可以理解为字段被过滤的概率 比如:性别的过滤因子是50%;
字段 | 过滤因子 |
name | 0.1% |
age | 10% |
sex | 50% |
对于不同的字段有不同的过滤因子,过滤因子越小,过滤的数据越多,查询的越少,在表user中,如果选
择sex为索引,那么将不是很好的选择,最直观的的印象就是sex这个字段,过滤不了多少数据,
扫描行数依旧非常大。
我们如果以name为索引,将会是一个更好的选择。或者可以建立一个组合索引(name,age,sex)
三星索引
《数据库索引与设计》一文中,三星索引指的是:
第一星:WHERE 条件等值作为组合索引最开头的列。
第二星:将order by加入索引中
第三星:将查询语句剩余的列加入索引中
对于如下语句:
select name,sex,age,id_card from user where name = 'xxx' and age = xx order by phone;
满足第一星的索引:(name,age),(age,name)
满足第二星的索引:(name,age,phone)(age,name,phone)
满足第三星的索引:(name,age,phone,id_card)(age,name,phone,id_card)
索引满足了三星索引的要求可以算的是优质索引,查询速率也会非常不错,不过就算不能满足三星,也尽可能满足多的星。
总结
说了那么多,其实索引的设计只要遵循一定的规律,还是不是很难的。
总而言之:索引的设计和sql语句的写法都息息相关,我们不仅仅要考虑
表的设计,也要考虑怎么写sql才能更好的设计索引。