使用“NOT IN”时非常慢的子查询

时间:2011-08-09 16:58:58

标签: ms-access query-optimization

我正在为大型预先存在的Access数据库中包含的数据生成报告(紧凑和修复后约500 MB),而我遇到了一个慢速子查询的问题。

数据库有一个大表,其中包含每个客户购买的记录。这是一个简单的查询,可以找到购买蓝色小部件的客户。它在几秒钟内完成并返回大约一万条记录。

SELECT DISTINCT CustomerId 
FROM ProductSales
WHERE Product = 'BLUE' 

这是一个查询,它试图找到购买蓝色小部件但不是红色小部件的客户。运行大约需要一个小时。

SELECT DISTINCT CustomerId FROM ProductSales
WHERE Product = 'BLUE' 
AND CustomerId NOT IN (
    SELECT CustomerId 
    FROM ProductSales 
    WHERE Product = 'RED'
)

有没有办法重构第二个查询,使其花费几分钟而不是一小时?

2 个答案:

答案 0 :(得分:11)

Access'数据库引擎不能使用Not In的索引,所以它一定很慢。使用CustomerId上的索引,此查询应该更快,因为数据库引擎可以使用索引。

SELECT DISTINCT blue.CustomerId
FROM
    ProductSales AS blue
    LEFT JOIN
        (
            SELECT CustomerId 
            FROM ProductSales 
            WHERE Product = 'RED'
        ) AS red
    ON blue.CustomerId = red.CustomerId
WHERE
        blue.Product = 'BLUE'
    AND red.CustomerId Is Null; 

您可能也可以尝试Not Exists方法,但无法保证索引的使用。另外,请参阅下面David Fenton的评论,其中更详细地讨论了性能影响。

答案 1 :(得分:0)

当然,如果您没有索引,请添加索引。如果这是一个问题,可能只是有很多客户订购RED以外的其他东西而不是BLUE那么多;这个(未经测试的)查询试图修复它。

SELECT DISTINCT CustomerId FROM ProductSales
LEFT JOIN (
  SELECT DISTINCT CustomerId cid FROM ProductSales
  LEFT JOIN (
    SELECT DISTINCT CustomerId
    FROM ProductSales
    WHERE Product = 'BLUE'
  ) foo ON CustomerId = cid
  WHERE Product = 'RED'
) bar USING (CustomerId)
WHERE cid IS NULL