【问题标题】:Decile ranking performance in NetezzaNetezza 中的 Decile 排名表现
【发布时间】:2012-09-07 18:28:05
【问题描述】:

我在 Netezza 中有一个小型(ish)聚合数据集,大约 1000 万行,位于 TwinFin 6 上。

为了简化问题,我减少了列数:

CUSTOMER_SALES_AGG

CUSTOMER_ID
NUMBER_TRANS
TOTAL_DOLLARS
TOTAL_ITEMS

此表分布在 CUSTOMER_ID 上,每个客户 ID 有 1 行,收集客户进行的总交易、他们花费的总美元以及他们购买的物品数量。

我正在尝试通过 # 次交易、总花费的美元和购买的总物品来计算每个客户在所有客户中的十分位排名。例如。如果客户花费 >= 90% 的其他客户,他们将排名第 1 个十分位。

我已经建立了一个查询:

SELECT
    CUSTOMER_ID, 
    NUMBER_TRANS,
    NTILE(10) OVER(ORDER BY NUMBER_TRANS DESC NULLS LAST) as TRANS_DECILE,
    TOTAL_DOLLARS,
    NTILE(10) OVER(ORDER BY TOTAL_DOLLARS DESC NULLS LAST) as DOLLARS_DECILE,
    TOTAL_ITEMS,
    NTILE(10) OVER(ORDER BY TOTAL_ITEMS DESC NULLS LAST) as ITEMS_DECILE
FROM CUSTOMER_SALES_AGG;

这可行,但它非常很慢,需要将近 10-20 分钟才能运行。

由于进行十分位数计算需要对数据进行排序,然后将排序后的数据分组,Netezza 的 MPP 结构似乎可以很好地处理这个问题。如果我对十分位数进行分区,我可以重新分配并在每个 SPU 上进行排名,它可能会更快。

关于如何加快速度的任何想法?

【问题讨论】:

  • 排名和排序本质上是可并行化的操作。我希望多处理器数据库能够有效地处理这些操作。但是,我不能谈论特定的 Netezza 操作。
  • 在某些方面,是的,确实如此。但是,对存在于单独的无共享系统上的数据进行排序需要对数据进行两次排序 - 在每个 SPU 上一次,然后在主机上再次对完整数据集进行排序..?
  • 。 .数据确实需要排序。如果正确实施,引擎将执行相当于快速排序的操作,以在处理器之间拆分数据,然后枚举结果,并在控制处理器上完成排序。这需要只发送一次数据——并且只发送被排名的字段——尽管还有额外的枚举和其他工作。此操作需要一些时间,但在合理的硬件上以秒而不是分钟为单位。
  • 同意,这基本上就是我认为它应该做的事情。我们的盒子上有 6 个 s-blade(我相信这意味着 48 个处理器)。
  • 你可以试试 row_number() 吗? Netezza 可能没有针对未分区的情况进行优化;似乎它正在将所有内容发送到一个处理器。他们可能会更好地优化 ROW_NUMBER()。如果是这样,您也许可以将查询重写为更有效的内容。

标签: sql netezza


【解决方案1】:

似乎主要问题源于在同一个 SQL 语句中使用了多个分析函数 (NTILE)(我的实际语句以 7 种不同的方式对客户进行排名)。

据我所知,正如@GordonLinoff 在 cmets 中解释的那样,Netezza 会在每个处理器上进行快速排序,并在控制器系统(Netezza 主机)上进行最终快速排序。但是,它只执行一次,然后,正如他所猜测的那样 - 将其全部推送到控制器系统。

它继续对控制器系统上的数据进行快速排序以用于剩余的分析功能,根本不使用并行性。我希望它应该以各种方式对数据进行排序,在每个处理器上,在主机上进行最终排序,然后将数据推送回处理器以进行每列的最终哈希连接。

我最终创建了一个类似这样的查询。

WITH 
NT AS (
  select customer_id, 
         number_trans,
         ntile(10) over (order by number_trans) as trans_decile
),
TD AS (
  select customer_id, 
         total_dollars,
         ntile(10) over (order by total_dollars) as dollars_decile
),
NI AS (
  select customer_id, 
         total_items,
         ntile(10) over (order by total_items) as items_decile
)
SELECT
    NT.CUSTOMER_ID, NT.NUMBER_TRANS, NT.TRANS_DECILE,
    TD.TOTAL_DOLLARS, TD.DOLLARS_DECILE,
    NI.TOTAL_ITEMS, NI.ITEMS_DECILE
FROM NT
JOIN TD ON (NT.CUSTOMER_ID = TD.CUSTOMER_ID)
JOIN NI ON (NT.CUSTOMER_ID = NI.CUSTOMER_ID);

这个查询的计划要复杂得多,但对于我进行 7 次分析排名的情况,查询时间从 12 分钟缩短到不到 5 分钟。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多