2011-08-09 89 views
6

我正在生成含有大量预先存在的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' 
) 

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

+0

我相信客户ID字段上有索引两个表中? –

+0

你试过SELECT DISTINCT客户编号FROM ProductSales WHERE产品= 'BLUE' 减SELECT客户编号FROM ProductSales WHERE产品= '红'。我已经看到它真正加快了查询的情况,但情况因人而异 –

+0

@Marc B:这里有只有一个表,但客户ID被索引就可以了。 – James

回答

10

访问数据库引擎不能使用索引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

Woah。从60分钟降到大约一秒钟。这比旧版本快3600倍。谢谢! :-)为了将来的参考,是否有一个SQL操作列表Access不在某处使用索引? – James

+1

这里可能有一个列表,但我不知道在哪里。 :-)如果你想坚持这一点,Google Jet ShowPlan ...将权威地告诉你数据库引擎如何在你的查询中使用索引。你可以在这里找到关于查询性能的详细讨论:http://msdn.microsoft.com/en-us/library/aa188211(office.10).aspx – HansUp

+1

这不是没有在和不存在从不使用索引 - 它是你无法预测他们什么时候会,什么时候不会。任何时候你都可以将一个NOT IN/EXISTS子查询重新设计成一个JOIN,你可能会提高性能。但是,这一切都取决于所得记录集的可编辑性 - JOIN中使用的一些子查询将使查询不可更新。 –

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