SQL语句中的NOT IN 的优化

SQL语句中的IN和NOT IN子查询理解起来很直观,和实际的业务也很匹配,所有经常被开发人员使用,数据量不大的表还好,如果数据量太大将导致性能问题。

原SQL:
SELECT COUNT(DISTINCT T.ID)
  FROM TASK T
 WHERE T.TENANT_KEY= 'TP18SQUME1'
   AND T.ID IN(
SELECT ENTITY_ID
  FROM SHARE_ENTRY
 WHERE ENTRY_TYPE= 'user'
   AND SID= 8005824118306255410)
   AND T.ID NOT IN(
SELECT DISTINCT S.TARGET_ID
  FROM STREAM S
 WHERE S.OPT_USER= 8005824118306255410
   AND S.TARGET_ID IS NOT NULL)
   AND T.CREATOR!= 8005824118306255410
   AND T.STATUS= 'todo'

由于IN和NOT IN会全表扫描,所有以上查询性能很低,耗时4s左右;

优化后的SQL:
SELECT COUNT(DISTINCT T.ID) FROM ((select ID from TASK  WHERE TENANT_KEY= 'TP18SQUME1' AND CREATOR!= 8005824118306255410 AND STATUS= 'todo') T 
left join (SELECT TARGET_ID FROM STREAM WHERE OPT_USER= 8005824118306255410) S ON T.ID = S.TARGET_ID
left join (SELECT ENTITY_ID FROM SHARE_ENTRY WHERE ENTRY_TYPE= 'user' AND SID= 8005824118306255410) E ON T.ID=E.ENTITY_ID) 
WHERE S.TARGET_ID IS NULL AND E.ENTITY_ID IS NOT NULL


用join链接查询代替IN和NOT IN查询可以大大提高效率,优化后的查询耗时0.2s。


SQL,`NOT IN` 用于从结果集排除那些匹配指定值集合的行。然而,这个操作对于大数据量的表可能会比较慢,因为它需要对整个指定集合进行全表扫描。为了优化`NOT IN` 的性能,可以考虑以下几个方面: 1. **索引使用**:如果可能,为包含`NOT IN`子句的列创建一个反向索引(如倒排索引)。这样,数据库可以直接通过索引来找到不匹配的行,而不是遍历整个表。 2. **避免冗余的`NOT IN`**:如果可能,尽量减少使用`NOT IN`,因为每次都会增加查询的复杂度。尝试改用`EXISTS` 或者 `LEFT JOIN` 来替代,比如查找不在子表的记录。 3. **分区和分片**:如果数据量非常大,并且表进行了分区或分片,可以针对`NOT IN` 子句的值范围进行分区查询,提高查询效率。 4. **子查询分解**:如果`NOT IN` 子句的结果是一个复杂的查询,尝试将其分解成两个独立的查询,然后合并结果。 5. **预计算列表**:如果`NOT IN` 的值集合是从另一个静态表获取的,可以预先计算好并存储起来,作为临时表,减少动态查询带来的性能损耗。 示例: ```sql -- 不推荐的方式 SELECT * FROM tableA WHERE id NOT IN (SELECT id FROM tableB); -- 可能更优的方式 CREATE INDEX idx_tableA_not_in_tableB ON tableA (id); SELECT * FROM tableA WHERE id NOT IN (SELECT DISTINCT id FROM tableB); -- 使用exists代替 SELECT * FROM tableA WHERE NOT EXISTS (SELECT 1 FROM tableB WHERE tableB.id = tableA.id); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值