要为每个类别选择 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来限制每个类别查询的记录数。
这在大表上效率极低,因为它会为所有记录分配 id,即使我们只对每个类别的 N 条记录感兴趣。
以下内容不适用于我正在使用的 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
更多信息:
我的数据按类别
进行物理分区,能够明确利用这一点会很有用
最佳答案
正如 @Lamak 在评论中提到的,您无法避免对表中的所有行进行排序,但不是出于所述原因。需要进行排序来确定对结果集进行分区的不同类别,并且在每个分区内没有显式排序的情况下,行号很容易确定为类别排序的副作用。
查询如何“在幕后”运行,或者,如果使用正确的术语,其执行计划由可能有助于避免该类别排序的索引的存在(或不存在)决定。如果您在 (category, value)
以及结果中需要的任何其他列上有覆盖索引,您的查询将运行得更加高效。
在后一种情况下,简化的算法可能看起来更像这样:
- 从索引中读取包含所有必需列(包括行号)的预排序记录。
- 丢弃行号大于
n
的记录。
您的“理想”查询
SELECT category, value, row_number() OVER (PARTITION by category) as category_id FROM myTable WHERE category_id < N
可能不会在任何 SQL 数据库中运行,因为 SELECT
列表是在 WHERE
子句谓词之后处理的,因此 当评估谓词时,category_id
是未知的。
关于sql - 如何高效查询每个类别的 n 条记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46609062/