minus 指令运用在两个 SQL 语句上,优化取两个语句查询结果集的技巧将差集。它先找出第一个 SQL 所产生的改写结果,然后看这些结果有没有在第二个 SQL 的为标结果中,如果在,量查那这些数据就被去除,优化不会在最后的技巧将结果中出现,第二个 SQL 结果集比第一个SQL结果集多的改写数据也会被抛弃。 这两天的为标优化工作中遇到这样一种案例,第一个SQL语句结果集很小,量查第二个SQL语句结果集很大,优化这种情况下我们怎么来优化处理呢?技巧将
创建测试表

创建存储过程,免费信息发布网向测试插入50万数据。改写(实际生产案例中表中数据有几千万)
注意下面的为标存储过程中,是量查GreatSQL在Oracle模式下创建的,GreatSQL实现了大量的Oracle语法兼容,比如下面存储过程中遇到的日期加减,add_months函数,while loop循环等,数据库由Oracle向GreatSQL迁移时,会节省很多代码改造工作。
复制set sql_mode=oracle; delimiter // create or replace procedure p1() as p1 int :=1; n1 int; d1 datetime; begin while p1<=500000 loop n1:=round(rand()*500000); d1:=to_date(2016-01-01,yyyy-mm-dd) + round(rand()*3000); insert into t1(subscriber_id,member_num,effectdate,expirydate,create_date) values(n1,concat(m_,n1),last_day(d1)+1,add_months(last_day(d1)+1,100),d1); set p1=p1+1; end loop; end; // delimiter ;1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.这个表create_date列的数据是从2016年1月到2024年3月的b2b供应网数据,使用了随机值,保证每个月的数据量相近,subscriber_id也是随机值生成的,选择性很好,这个模型数据与生产环境差不多。
执行下面这个SQL语句:
复制SELECT DISTINCT subscriber_id, member_num FROM t1 WHERE create_date >= 2024-02-01 AND create_date < 2024-03-01 AND to_char(effectdate, yyyymm) > 202402 minus SELECT DISTINCT subscriber_id, member_num FROM t1 WHERE 202402 BETWEEN to_char(effectdate, yyyymm) AND to_char(expirydate, yyyymm);1.2.3.4.5.6.7.8.9.10.这条SQL是根据生产环境使用的语句简化而来的,只为突出本文要说明的知识点。
此SQL的执行计划如下:
复制greatsql> explain analyze -> select distinct subscriber_id, member_num -> from t1 -> where create_date >= 2024-02-01 -> and create_date < 2024-03-01 -> and to_char(effectdate, yyyymm) > 202402 -> minus -> select distinct subscriber_id, member_num -> from t1 -> where 202402 between to_char(effectdate, yyyymm) and -> to_char(expirydate, yyyymm)\G源码下载