【问题标题】:MS Access 2010 SQL Top N query by group performance issue (continued2)MS Access 2010 SQL Top N 查询按组性能问题(续 2)
【发布时间】:2014-06-25 09:33:52
【问题描述】:

我已经改写了之前的问题MS Access 2010 SQL Top N query by group performance issue (continued),因为我认为之前没有清楚地描述上下文。我上一个问题的答案没有按组提供前 n 个结果。改写的问题更笼统。我现在将所有数据都放在一个表中。

这是我的情况:我有一个表(分析),其中包含各种类别(类别)的产品(零件编号)。每个产品都有一个价格(价值)。查询的目标是显示每个类别中价格最高的 10 个产品。该表包含 15000 条记录,并且会继续增长。

这是查询:

  SELECT 
    a.Location,
    a.Category,
    a.Partnumber
    a.Value

  FROM Analysis a

  WHERE a.Partnumber IN (
    SELECT TOP 10 aa.Partnumber
    FROM Analysis aa
    WHERE aa.Category = a.Category
    ORDER BY aa.Value DESC
  )


  ORDER BY 
    a.Category;

这是我的问题:我当前的查询使用表中的 1000 条记录(响应时间 3 秒)。对于 15000 条记录,查询会无限运行。如何重建查询以显着提高性能?

我上一个问题的答案是不使用列表内操作。但是这个消除了按组给出前 n 条记录的功能。查询给出了所有记录的前 n 个。

【问题讨论】:

  • 您可以尝试使用排名查询,如图所示here

标签: sql performance ms-access-2010 query-performance


【解决方案1】:

对于名为 [Analysis] 的表中的样本数据

ID  Location   Category  Partnumber  Value
--  ---------  --------  ----------  -----
 1  here       cat1      part001         1
 2  there      cat1      part002         2
 3  wherever   cat1      part003         3
 4  someplace  cat2      part004         4
 5  nowhere    cat2      part005         5
 6  unknown    cat2      part006         6

“排名查询”

SELECT 
    a1.ID,
    a1.Location,
    a1.Category,
    a1.Partnumber,
    a1.Value,
    COUNT(*) AS CategoryRank
FROM
    Analysis a1
    INNER JOIN
    Analysis a2
        ON a1.Category = a2.Category
            AND a1.Value <= a2.Value
GROUP BY
    a1.ID,
    a1.Location,
    a1.Category,
    a1.Partnumber,
    a1.Value

返回

ID  Location   Category  Partnumber  Value  CategoryRank
--  ---------  --------  ----------  -----  ------------
 1  here       cat1      part001         1             3
 2  there      cat1      part002         2             2
 3  wherever   cat1      part003         3             1
 4  someplace  cat2      part004         4             3
 5  nowhere    cat2      part005         5             2
 6  unknown    cat2      part006         6             1

因此,如果您只想要每个类别中的前 2 个项目,只需将上述查询包装在 SELECT ... WHERE 中

SELECT *
FROM
(
        SELECT 
            a1.ID,
            a1.Location,
            a1.Category,
            a1.Partnumber,
            a1.Value,
            COUNT(*) AS CategoryRank
        FROM
            Analysis a1
            INNER JOIN
            Analysis a2
                ON a1.Category = a2.Category
                    AND a1.Value <= a2.Value
        GROUP BY
            a1.ID,
            a1.Location,
            a1.Category,
            a1.Partnumber,
            a1.Value
) AS RankingQuery
WHERE CategoryRank <= 2
ORDER BY Category, CategoryRank

给你

ID  Location  Category  Partnumber  Value  CategoryRank
--  --------  --------  ----------  -----  ------------
 3  wherever  cat1      part003         3             1
 2  there     cat1      part002         2             2
 6  unknown   cat2      part006         6             1
 5  nowhere   cat2      part005         5             2

注意:确保为 [Category] ​​和 [Value] 字段编制索引以获得最佳性能。

【讨论】:

  • 我只是在玩自己的内部排名查询,它以一种不稳定的方式处理重复值。解决方案很棒,只是对一般技术的一个小警告。
  • @VBlades 是的,好点。使用这种方法时,重复项可能会给事情带来麻烦。 :(
  • 我已经用排名查询测试了这个建议。响应时间与我的查询相同或更差。带有索引的提示非常有帮助。我已经对 [Category] ​​和 [Partnumber] 进行了索引,因此响应时间得到了显着改善。我注意到每个类别的零件编号越少,在记录总数相同的情况下响应时间就越快。例如。有 9 个类别和 16000 个零件编号,响应时间为 40 秒。对于 60 个类别和 16000 个零件编号,响应时间为 11 秒。因此这个问题得到了回答。谢谢!
  • @Daniel 很高兴听到改进。是的,数据的分布肯定会影响执行时间,因此您可能应该测试两个查询,看看哪一个更适合您的特定数据集。另请注意,[Value] 也应该被索引。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-22
相关资源
最近更新 更多