在SQL Server中为啥不建议使用Not In子查询

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在SQL Server中为啥不建议使用Not In子查询相关的知识,希望对你有一定的参考价值。

not in查询效率低,容易出现bug,所以不建议使用,使用not in查询时,如果查询语句使用了not in,那么对内外表都进行全表扫描,没有用到索引;而not exists的子查询依然能用到表上的索引。所以无论哪个表大,用not exists都比not in 要快。
参考:http://my.oschina.net/u/2308739/blog/497643
参考技术A not in是不会用到索引的,是全表扫描,会影响效率。

如何在 SQL 子查询中使用 NOT IN? [复制]

【中文标题】如何在 SQL 子查询中使用 NOT IN? [复制]【英文标题】:How to use NOT IN in an SQL subquery? [duplicate] 【发布时间】:2020-05-16 03:26:53 【问题描述】:

我正在尝试查找饮酒者和饮酒者喜欢的饮品,但饮酒者到目前为止还没有订购该饮品。我还需要按饮酒者和饮料的升序对饮酒者和饮料对进行排序。

注意:我只能使用 IN 或 NOT IN 操作。 (我也在 MYSQL 工作)

我对 SQL 非常陌生,因此非常感谢任何建议。

这是我试图从中检索数据的两个表:

CREATE TABLE LIKES( /* Drinkers like drinks */
DRINKER     VARCHAR(30) NOT NULL,   /* Drinker name */
DRINK       VARCHAR(30) NOT NULL,   /* Drink name   */
RATING      DECIMAL(1)  NOT NULL,   /* Rating of the drink  */
    CONSTRAINT LIKES_PKEY PRIMARY KEY(DRINKER, DRINK),
    CONSTRAINT LIKES_FKEY1 FOREIGN KEY(DRINK) REFERENCES ALLDRINKS(DRINK),
    CONSTRAINT LIKES_DKEY2 FOREIGN KEY(DRINKER) REFERENCES DRINKERS(DRINKER));

CREATE TABLE ORDERS(    /* Drinkers visit pubs and consumes drinks */
DRINKER     VARCHAR(30) NOT NULL,   /* Drinker name */
PUB         VARCHAR(30) NOT NULL,   /* Pub name */
ODATE       DATE        NOT NULL,   /* Order date   */
DRINK       VARCHAR(30) NOT NULL,   /* Drink name   */
DRINK_NO    DECIMAL(2)  NOT NULL,   /* A sequence number of a drink */
    CONSTRAINT ORDERS_PKEY PRIMARY KEY(DRINKER, PUB, ODATE, DRINK, DRINK_NO),
    CONSTRAINT ORDERS_FKEY1 FOREIGN KEY(PUB, DRINK) REFERENCES SERVES(PUB, DRINK),
    CONSTRAINT ORDERS_FKEY2 FOREIGN KEY(DRINKER) REFERENCES DRINKERS(DRINKER)   );

这是我的 SELECT 语句:

SELECT DRINKER, DRINK
FROM LIKES
WHERE DRINKER NOT IN 
    (SELECT DRINKER
     FROM ORDERS 
     WHERE ODATE IS NULL)
     AND DRINK NOT IN
         (SELECT DRINK 
          FROM ORDERS 
          WHERE ODATE IS NULL)
          ORDER BY DRINKER AND DRINK ASC; 

【问题讨论】:

【参考方案1】:

除了常见的条件ODATE IS NULL之外,您还可以在子查询中简单地使用NOT EXISTS结合两列:

SELECT l.DRINKER, l.DRINK
  FROM LIKES l
 WHERE NOT EXISTS 
      ( SELECT 0
          FROM ORDERS 
         WHERE ODATE IS NULL
           AND ( DRINKER = l.DRINKER
              OR DRINK = l.DRINK ) )
 ORDER BY l.DRINKER , l.DRINK;

Demo

【讨论】:

我正在起草相同的答案,考虑如下ODATE is not null columnShould be using exists @Barbaros Özhan 我只能使用 IN 或 NOT IN 操作【参考方案2】:
SELECT l.DRINKER, l.DRINK
FROM LIKES l
WHERE CONCAT(l.DRINKER+'~~'+l.DRINK) NOT IN 
( 
   SELECT CONCAT(O.DRINKER+'~~'+O.DRINK)
   FROM ORDERS O
)
ORDER BY l.DRINKER , l.DRINK ASC;

【讨论】:

我用过这个,但是我仍然收到喜欢并订购饮料的饮酒者的名字。我应该只收到喜欢喝但没有点的饮酒者的名字。 @Noods:我已根据要求修改了查询。请检查

以上是关于在SQL Server中为啥不建议使用Not In子查询的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 SQL 查询中 NOT IN 比 IN 慢得多

Not in 子句不使用开放查询过滤 SQL Server

Sql server not in 子句不起作用

SQL SERVER 不支持多字段的IN 和 NOT IN

SQL SERVER 不支持多字段的IN 和 NOT IN

Sql server not in优化