2

要为每个类别选择 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,能够显式利用这将是有用的

4

2 回答 2

4

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

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

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

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

您的“理想”查询

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

可能不会在任何 SQL 数据库中运行,因为SELECT列表是在子句谓词之后处理的,因此何时评估谓词是未知的。WHEREcategory_id

于 2017-10-06T19:28:51.100 回答
0

行号的其他方法,但我也对性能有疑问。我同意@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                                                 
于 2017-10-07T07:40:24.743 回答