让查询飞起来:基于索引的 SQL 优化技巧

1. 前言

今天,小编给大家分享点干货,工作中都能用到的东西。是什么呢?那就是Mysql的性能优化,我们一起来看看吧。

2. 优化方式

好的,现在我们先来看看有哪些优化方式,然后再这些优化方式当中,我们程序员需要掌握其中的哪些优化方式。

数据库层面的优化

表的结构是否正确?三范式是否有正确的索引来提高查询效率?索引是否为每个表使用了适当的存储引擎?存储引擎每个表是否使用适当的行格式?字段压缩方式是否使用了适当的锁策略?事务的隔离级别用于缓存的所有内存区域的大小是否正确?buffpool

硬件层面的优化

硬盘cpu内存宽带

上面这些优化方式,是mysql官网里面有的。针对这些优化点,对于我们程序员来说,是不是只需要关注数据库层面的优化。数据库层面的优化中我们是不是只需要着重关注索引的优化,所以今天小编会分享一些索引方面的优化点。

3. 慢日志查询

知道了优化点,那我们为什么要优化呢?肯定是执行时间太慢,并发能力上不去。所以,我们需不需要优化就需看我们执行的时间是否满足我们的需求。那我们怎么知道执行时间是否满足我们的需要呢?这个就要看我们的慢日志了。

慢日志参数:

long_query_time: 超过多少秒进入慢查
复制
SELECT @@long_query_time;--默认是10单位S SET GLOBAL long_query_time=1;--设置超过1s就算慢查1.2.
min_examined_row_limit: 检索查询的数量的行如果低于这个值,不进入慢查。
复制
SELECT @@min_examined_row_limit;--默认是01.
log_output: 慢日志保存方式
复制
SELECT @@1og_output;--慢查存在哪里 SET GLOBAL log_output=table,file; -- table:表 file:文件1.2.

如果是file,那么保存的文件路径为slow_query_log_file。

复制
SELECT @aslow_query_log_file; -- 查询慢日志存放路径 SET GLOBAL slow_query_log_file=; -- 设置慢日志存放路径1.2.

如果是table,则保存在mysql.slow_log表中。

slow_query_log:  慢日志开关
复制
SELECT @@slow_query_log; -- 查询慢日志开关 SET GLOBAL slow_query_log=1; -- 开启慢查1.2.

4. sql语句优化

Explain执行计划

建立索引建立在where、orderby、groupby的字段上面,提升查询性能;但是就算加了也不一定能走到索引,所以要学会Explain分析。

Explain输出字段

这些字段里面,我们只关注里面几个就行了。

type列:  这一列显示了访问类型,即MySQL决定如何查找表中的行。

依次从好到差:system,const,eq_ref,ref,fulltext,ref_or_null,unique_subquery,index_subquery,range,index_merge,index,ALL。

这个我们需要优化到 range 级别。
复制
EXPLAIN select * FROM product WHERE id=1; -- const 只有一个匹配行并且id是主键 EXPLAIN select product_price FROM product WHERE product_price=55 -- ref 查询非唯一索引或主键的索引值 EXPLAIN select * FROM product WHERE id in(1,2); -- range 范围扫描 EXPLAIN SELECT * FROM product INNER JOIN product_price on product_new.id=product.product_id; -- eq_ref 组合查询中,用到了主键或者唯一索引 EXPLAIN SELECT product_price FROM product ORDER BY product_price; -- index类型 扫描索引树 比all相对来讲要快 EXPLAIN SELECT product_tag FROM product ORDER BY product_tag; -- all 不是索引,没有对应的索引树一般数据量大的情况下是需要优化的1.2.3.4.5.6.
possible_keys: 可以选择的索引查询,如果为null则没有索引可以供选择。key: 真正使用的索引rows: 执行查询必须扫描的行数,对于InnoDB来讲,这个是个预估值,不是非常准确,但是行数越少,性能肯定越好。Extra

Using filesort: 排序没有走到索引

Using index 在索引树中能遍历到想要的数据(覆盖索引)

Using index condition 索引条件下推

Using index for group-by group by分组基于索引检索

Using temporary 是否使用临时表,一般在 group by与order by场景

Using where 扫描出来的数据需要进行where匹配

order by优化

如果让orderby的字段走索引,那么排序流程直接可以在索引树完成,如果排序的字段不走索引,整个排序流程必须先把数据放到内存,在内存实现排序。

怎么判断是否orderby用到了索引?

如果输出Extra的列 EXPLAIN 不包含 Using filesort,则使用了索引

如果输出Extra列 EXPLAIN 包含 Using filesort,则没有使用索引

count优化

count()是一个聚合函数,对于返回的结果集 的一个统计,一行一行去判断,如果count括号里的不是null,那么计值+1,否则不加,最后返回一个累计的总数。

count(*):* 是整条数据,也进行了优化,因为整条数据肯定不会为null。所以也不需要去判断

count(1):1 是扫描到数据 扫描到了就固定返回一个1,肯定不为null,不会做null判断。

count(id):id 主键id,肯定不为null,也不会去判断null,但是相对于count(1)来讲,要去解析ID。稍微慢点,但是也可以忽略不计。

count(字段):这个就有影响了,因为扫描行出来,需要判断字段是否为空。

Limit优化

limit m,n ; 扫描m+n条数据,然后过滤掉前面的m条数据,当m越大,那么需要扫描的数据也就越多,性能也会越来越慢。

复制
EXPLAIN SELECT * FROM product LIMIT 100000,10 --很慢很慢1.

针对这种情况,有以下几种方案可以进行一定的优化。

如果id是趋势递增的,那么每次查询都可以返回这次查询最大的ID,然后下次查询,加上大于 上次最大id的条件,这样会通过主键索引去扫描,并且扫描数量会少很多很多。因为只需要扫描where条件的数据
复制
SELECT * FROM product WHERE id > 100000 ORDER BY id LIMIT 10 -- 根据id查询,并且使用where过滤1.
先limit出来主键ID,然后用主表跟查询出来的ID进行inner join 内连接,这样,也能一定上提速,因为减少了回表,查询ID只需要走聚集索引就行。
复制
SELECT * FROM product INNER JOIN( SELECT id FROM product ORDER BY id LIMIT 100000,10 ) a ON product_new.id=a.id1.2.3.4.
分库分表

如果sql语句用到了索引,但是查询还是很慢,那么看看数据库表中的数据是否过多或者并发是不是很高。如果并发很高,那么我们可以考虑分库,比如order和product,把业务细化。如果表数据过多,那就需要分表,当然我们也可以引入第三方组件解决数据过多的问题,比如Elasticsearch。

5. 总结

对于上面的优化,基本上都是基于索引的。基于索引的 SQL 优化旨在通过合理设计和使用索引来提升查询性能。索引可以加速数据检索,减少全表扫描,特别是在处理大量数据时。优化策略包括选择合适的索引类型(如单列索引、复合索引)、避免冗余索引、使用覆盖索引来避免访问表数据、并通过 EXPLAIN 分析查询执行计划来确保索引的有效使用。合理设计索引不仅能加速查询,还能减少数据库负担,提高整体性能。

THE END
本站服务器由亿华云赞助提供-企业级高防云服务器