一次SQL优化处理

来源:这里教程网 时间:2026-03-03 21:38:38 作者:

背景

研发在预生产环境上线一个 SQL ,执行时间耗时 6s ,研发通过加索引、排查隐式转换等方式,经过初步优化后,耗时 2s

需求

想让 dba 给协助看下是否还有优化空间

处理过程

1、先看下面这个已经初步优化过的例子(左连接中的主表优先作用查询条件):

SELECT    a.*,           c.transaction FROM      (               SELECT   resource_id               FROM     user_desc d                    WHERE    isdelete = 0                    AND      user_code = 'ac160589'                    ORDER BY sale_code limit 20) a LEFT JOIN           (               SELECT   resources_id sum(ifnull(allocation, 0) * 12345) transaction               FROM     my_resources                    GROUP BY resources_id) c ON        a.resource_id = c.resources_id;  

2、该语句还存在其它问题。不难看出子查询 c 是全表聚合查询,在表数量特别大的情况下会导致整个语句的性能下降。

其实对于子查询 c ,左连接最后结果集只关心能和主表 resource_id 能匹配的数据。因此我们可以重写语句如下,执行时间从原来的 2 秒下降到 2 毫秒。 SELECT    a.*,           c.transaction FROM      (                    SELECT   resource_id                    FROM     user_desc d                    WHERE    isdelete = 0                    AND      user_code = 'ac160589'                    ORDER BY sale_code limit 20) a LEFT JOIN           (                    SELECT   resources_id sum(ifnull(allocation, 0) * 12345) transaction                    FROM     my_resources r,                             (                                      SELECT   resource_id                                      FROM     user_desc d                                      WHERE    isdelete = 0                                      AND      user_code = 'ac160589'                                      ORDER BY sale_code limit 20) a                    WHERE    r.resources_id = a.resources_id                    GROUP BY resources_id) c ON        a.resource_id = c.resources_id;

3、但是子查询 a 在我们的SQL语句中出现了多次。这种写法不仅存在额外的开销,还使得整个语句显的繁杂。使用 WITH 语句再次重写:

WITH a AS (          SELECT   resource_id          FROM     user_desc d          WHERE    isdelete = 0          AND      user_code = 'ac160589'          ORDER BY sale_code limit 20) SELECT    a.*,           c.transaction FROM      a LEFT JOIN           (                    SELECT   resources_id sum(ifnull(allocation, 0) * 12345) transaction                    FROM     my_resources r,                             a                    WHERE    r.resources_id = a.resources_id                    GROUP BY resources_id) c ON        a.resource_id = c.resources_id;

4、总结

数据库编译器产生执行计划,决定着 SQL 的实际执行方式。但是编译器只是尽力服务,所有数据库的编译器都不是尽善尽美的。 上述提到的多数场景,在其它数据库中也存在性能问题。了解数据库编译器的特性,才能避规其短处,写出高性能的 SQL 语句。 程序员在设计数据模型以及编写 SQL 语句时,要把算法的思想或意识带进来。编写复杂 SQL 语句要养成使用 WITH 语句的习惯。简洁且思路清晰的 SQL 语句也能减小数据库的负担。

相关推荐