如何有效地查询每个类别的n条记录

时间:2017-10-06 15:22:36

标签: sql select db2 partition bigsql

要为每个类别选择N条记录,可以执行以下操作:

SELECT category, category_id, value FROM
(
    SELECT category, value, row_number() OVER (PARTITION by category) as category_id
    FROM myTable
)
WHERE  category_id < N;

内部SELECT将首先按类别对记录进行分区,并为每个类别分配一个名为category_id的id。 然后,外部查询将使用category_id来限制它按类别查询的记录数。

这对于BIG表非常低效,因为即使我们只对每个类别的N条记录感兴趣,它也会通过为所有记录分配ID。

以下内容对我正在使用的sql引擎不起作用 - 不确定它是否适用于任何引擎。

SELECT category, value, row_number() OVER (PARTITION by category) as category_id
FROM myTable
WHERE category_id < N

有没有人知道以更好的时间复杂度实现这一目标的任何其他方法?

更多想法:

针对上述查询对以下算法进行时间分析可能会提供有关查询如何在场景后运行的更多见解:

   1. SELECT DISTINCT(category) FROM myTable
   2. FOREACH category SELECT N rows

更多信息: 我的数据由category进行物理分区,能够明确地利用那些有用的数据

2 个答案:

答案 0 :(得分:4)

正如@Lamak在评论中提到的那样,你无法避免对表中的所有行进行排序,但不能因为所述的原因而排序。需要排序来确定应该对结果集进行分区的不同类别,并且在每个分区中没有明确排序的情况下,行号很容易被确定为类别排序的副作用。

查询如何“在幕后”运行,或者,如果使用正确的术语,其执行计划由索引的存在(或不存在)决定,该索引可能有助于避免该类别排序。如果您在(category, value)上有覆盖索引,并且在结果中需要其他任何列,那么您的查询将更有效地运行。

在后一种情况下,简化算法看起来可能更像:

  1. 从索引中读取包含所有必要列(包括行号)的预排序记录。
  2. 丢弃行号大于n的记录。
  3. 您的“理想”查询

    SELECT category, value, row_number() OVER (PARTITION by category) as
    category_id FROM myTable WHERE category_id < N
    

    可能不会在任何SQL数据库中运行,因为在 SELECT子句谓词后处理 WHERE列表,因此category_id未知对谓词进行评估。

答案 1 :(得分:0)

rownumber的其他方法,但我对性能也有疑问。我同意@mustaccio。我的例子需要5行......

select distinct f1.category, f3.*             
from yourtable f1                        
inner join lateral                                          
(                                                           
 select f2.value from yourtable f2              
 where f2.category=f1.category 
 fetch first 5 rows only                                    
) f3 on 1=1