【问题标题】:How to EFFICIENTLY query n records per category如何有效地查询每个类别的 n 条记录
【发布时间】:2018-03-18 10:57:04
【问题描述】:

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

【问题讨论】:

  • 即使您的第二个查询可以在某些 RDBMS 上运行,执行计划也可能与第一个相同
  • 您可以尝试将派生表转储到#temp 并在其上创建索引,然后查询它
  • 用您正在使用的数据库标记您的问题。
  • @LONG 要动态转储到临时表中(保证每个类别至少包含 N 条记录),我将需要执行类似的查询。如果您知道另一种方法,请在答案中写出来。
  • 您的示例查询没有多大意义——您返回的 n 行每行都包含相同的值 (category),您不妨硬编码它。你能用更现实的查询更新问题吗?

标签: sql select db2 partition bigsql


【解决方案1】:

正如@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 列表是在WHERE 子句谓词之后处理的,因此在评估谓词时category_id 是未知的。 p>

【讨论】:

  • 在我的例子中,表在 hdfs 上由 category 物理分区,db2 似乎不够聪明,无法利用它。
  • 您可能想要更详细地描述您的软件堆栈。 DB2 本身不知道也不关心 hdfs。您是在谈论 BigSQL,可能是吗?
  • 你们知道 ibm InfoSphere BigInsights 中的哪个组件创建了执行计划吗?
【解决方案2】:

行号的其他方法,但我也对性能有疑问。我同意@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                                                 

【讨论】:

    猜你喜欢
    • 2019-01-17
    • 1970-01-01
    • 2020-06-21
    • 2010-09-23
    • 2021-06-25
    • 1970-01-01
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多