最近在知乎上发起了一个SQL优化挑战赛,本文为题目1的解析。其中涉及索引失效,修饰子查询重写等优化知识点,希望对大家在学习优化SQL的过程中有所帮助。
本文所使用的执行计划可视化工具为 PawSQL Explain Visualizer , 支持MySQL\PostgreSQL\openGauss等数据库,用户可以免登录使用。
题目:下面的SQL如何优化性能最佳
select * from customer
where c_custkey = ( select max(o_custkey) from orders
where subdate(o_orderdate, interval '1' DAY) < '2022-12-20')表定义如下:
create table customer (c_custkey int not null,c_name varchar(25),c_address varchar(40),c_nationkey int,c_phone char(15),c_acctbal decimal(15,2),c_mktsegment char(10),c_comment varchar(117), primary key pk_idx1614428511 (c_custkey)
) engine=innodb default charset=utf8mb4 collate=utf8mb4_bin;
-- tpch.orders definition
create table orders (o_orderkey int,o_custkey int,o_orderstatus char(1),o_totalprice decimal(15,2),o_orderdate date,o_orderpriority char(15),o_clerk char(15),o_shippriority int,o_comment varchar(79), primary key (o_orderkey)
) engine=innodb default charset=utf8mb4 collate=utf8mb4_0900_ai_ci;
orders表的字段上添加一个覆盖索引,并重写SQL
CREATE INDEX date_custkey_idx ON public.orders USING btree (o_orderdate, o_custkey);
重写后的SQL:
select * from customer where c_custkey = ( select max(o_custkey) from orders where o_orderdate < date('2022-12-20') + interval'1 DAY');
orders表上新增不同顺序的一个覆盖索引,同时通过order by limit 1重写max函数
CREATE INDEX date_custkey_idx2 ON public.orders USING btree (o_custkey, o_orderdate);
重写后的SQL:
select * from customer where c_custkey = ( select o_custkey from orders where o_orderdate < date('2022-12-20') + interval'1 DAY' order by o_custkey desc limit 1);
优化第一步选择 (o_orderdate, o_custkey)索引,通过覆盖索引获取数据时,需要找出 o_orderdate 小于 2022-12-21 的所有索引节点,然后遍历其中的 o_custkey,找出最大的值。优化第二部选择 (o_custkey, o_orderdate),通过覆盖索引获取数据时,需要按照 o_custkey 从大到小查找索引,找出其中 o_orderdate 小于 2022-12-21 的第一个索引节点即可。
我们将待优化SQL直接提交到PawSQL,让其给我们做自动优化。从输出的优化详情页面我们可以看到,PawSQL自动帮我们进行了以下两个重写优化
并且根据重写后的SQL推荐了对应的索引。使用PawSQL,真正做到了一键优化!
PawSQL Cloud关于题目1的优化详情:

PawSQL专注数据库性能优化的自动化和智能化,支持MySQL,PostgreSQL,Opengauss等,提供的SQL优化产品包括