- limit优化:若为limit 999999 10 则为从第一行起定位至999999行,然后再扫描处后10行,相当于全表扫描,性能很低。
- 若id为自增,则可以用id>行数 limit 条数。因为这种方式利用了id索引直接定位到行数,然后再扫描条数,相当于一个range扫描。
- 如:Select * from artist limit 100000,10 可优化为: select * from artist a join (select id from artist limit 100000,1) b on a.id >= b.id limit 10。以上优化思路是先取出100000行后面的1条记录id,然后采用表内连接,取出10条。
- Cout(*)优化:
- 采用非聚集索引(也称辅助索引)。因为非聚集索引不存放数据,而是有个指针指向数据,所以统计时消耗的资源更少,速度也更快。
- 如 select count(*) from user 可优化为:select count(非聚集索引)
- 注意:生产环境慎重使用select count(*)、select sum()。因为innoDB引擎(OLTP联机事务处理),它不像MyISAM引擎(OLAP联机分析处理)那样内置了一个计数器,在count时,直接从计数器取数据。innoDB必须全表扫描,而且会锁表(表级锁,不是行锁),当数据达到千万级别时,速度很慢,一个SQL就会让数据库挂掉。
- Count(distinct)优化:
- 最有效的方法是利用索引来做排重操作,先把排重打记录查找出来在通过count统计。
- 如:select count(distinct k) from user 可优化为:select count(*) from (select distinct k from user) tmp
- or 优化:
- 由于使用or条件的字段不会命中索引,索引可以使用union all
- 如以下name age 都建立索引。Select * from user where name ='a' or age=19 可优化为:Select * from user where name ='a' union all Select * from user where age=19
- having 优化:
- 使用where子句替换having子句
- 因为having只会在检索出所有记录才对结果过滤,这个处理需要排序、总计等操作。若能通过where限制,则可检索此方面的开销。
- like 优化:
- like '%book%' 不能命中索引,而'book%'可以命中。可以通过覆盖索引解决
- 如普通的查询为:select count(*) from artist where name like '%queen%'。此条数据则无法命中索引。
- 通过覆盖索引方法可解决
- 可事先设置主键id为聚集索引,所以数据都保存在了叶子结点,从索引中就可取出id列,而不必读取数据行(只要select 字段正好是索引,就用到了覆盖索引,通过覆盖索引可以减少I/O,提升性能。简单说就是在书里找个内容,由于目录很详细,在目录就找到了,而不必在翻到该页中查看)
- Select * from artist a left join (select id from artist where name like '%queen%') b on a.id = b.id
- join 优化:
- MySQL实现join的原理,原来MySQL内部采用了一种叫做 nested loop join的算法。Nested Loop Join 实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。
- 优化left join:
- 条件中尽量能够过滤一些行将驱动表变得小一点,用小表去驱动大表
- 右表的条件列一定要加上索引(主键、唯一索引、前缀索引等),最好能够使type达到range及以上(ref,eq_ref,const,system)
- 索引无法命中的情况:
- %字段%
- 使用or条件的字段
- 使用函数的字段
- Where string类型时不加单引号。如以下情况不会命中name索引:select * from uere where name=100 而 select * from uere where name='100'会命中
- 表很小,大约少于10行,这个没有什么危害,因为即使你有索引,优化器也会判断在边读索引边取数据时,直接全表扫描快些
- 你在一个where字句中使用含有索引的列,但这个列的值很集中化,比如字段 gender,这个的值就两个值male 和 female,如果使用索引反而会慢些,不使用索引会更快,这种情况不用担心
- 这个跟第上条类似,就是当你的一个索引,他的每个键对应多个值,即基数很低(low cardinality),因此可能会选择全表扫描
- 表编码不同
- 最左前缀匹配原则:
- 在mysql建立联合索引时会遵循最左前缀匹配的原则,即最左优先,在检索数据时从联合索引的最左边开始匹配
- 示例:对列col1、列col2和列col3建一个联合索引 KEY test_col1_col2_col3 on test(col1,col2,col3);联合索引 test_col1_col2_col3 实际建立了(col1)、(col1,col2)、(col,col2,col3)三个索引。
- SELECT * FROM test WHERE col1=“1” AND clo2=“2” AND clo4=“4”这个查询语句执行时会依照最左前缀匹配原则,检索时会使用索引(col1,col2)进行数据匹配。
- 索引的字段可以是任意顺序的,如:SELECT * FROM test WHERE col1=“1” AND clo2=“2”等价于 SELECT * FROM test WHERE col2=“2” AND clo1=“1”
- 只要不是其中某个过滤字段在大多数场景下能过滤90%以上的数据,而其他的过滤字段会频繁的更新,一般更倾向于创建组合索引
- 避免使用子查询,可用left join表连接取代之。
- 统计记录时可去掉不必要的排序
- Where、order by、group by、join、distinct union 后面的字段最好加上索引
【两只鱼】SQL 调优之13条锦囊妙计
2020-06-14 17:39:28
浏览数 (1)