我正在阅读 Hadoop:Tom White 的权威指南。在第 13.6 章“HBase 与 RDMS”中,他说如果你有大量数据,即使是像获取 10 个最近的项目这样的简单查询也非常昂贵,他们必须使用 python 和 PL/SQL 重写它们。
他以以下查询为例:
SELECT id, stamp, type FROM streams
WHERE type IN ('type1','type2','type3','type4',...,'typeN')
ORDER BY stamp DESC LIMIT 10 OFFSET 0;
并说:“RDBMS 查询计划器按如下方式处理此查询:
MERGE (
SELECT id, stamp, type FROM streams
WHERE type = 'type1' ORDER BY stamp DESC,
...,
SELECT id, stamp, type FROM streams
WHERE type = 'typeK' ORDER BY stamp DESC
) ORDER BY stamp DESC LIMIT 10 OFFSET 0;
这里的问题是我们只关注前 10 个 ID,但查询计划器实际上实现了整个合并,然后在最后进行限制。.... 实际上,我们甚至编写了一个执行堆排序的自定义 PL/Python 脚本。...在几乎所有情况下,这都优于本机 SQL 实现和查询计划器的策略...
预期性能和实验结果
我无法想象数据集会导致您必须编写 pl/python 才能正确执行如此简单的查询。所以我玩了一段时间关于这个问题并提出了以下意见:
这种查询的性能受到 O(KlogN) 的限制。因为它可以翻译成这样的东西:
SELECT * FROM (
SELECT id, stamp, type FROM streams
WHERE type = 'type1' ORDER BY stamp DESC LIMIT 10,
UNION
...,
SELECT id, stamp, type FROM streams
WHERE type = 'typeK' ORDER BY stamp DESC LIMIT 10
) t ORDER BY stamp DESC LIMIT 10;
(注意每个查询中的'LIMIT 10'。顺便说一句,我知道我不能限制和订购联合,但为了便于阅读,我已经去掉了包装选择)
每个子查询的运行速度应该与在索引 O(logN) 中找到正确位置并返回 10 个项目一样快。如果我们重复 K 次,我们得到 O(KlogN)。
即使查询计划器非常糟糕以至于它无法优化第一个查询,我们也可以始终将其转换为带有联合的查询并获得所需的性能,而无需在 pl/python 中编写任何内容。
为了仔细检查我的计算,我在一个填充了 9,000,000 条测试记录的 postgresql 上运行了查询。结果证实了我的预期,两个查询都非常快,第一个查询为 100 毫秒,第二个查询为 300 毫秒(带有联合的查询)。
因此,如果查询在 100 毫秒内运行 9,000,000 (logn=23) 条记录,那么对于 9,000,000,000 (logn=33) 条记录,它应该在 140 毫秒内运行。
问题
- 您在上述推理中发现任何缺陷吗?
- 你能想象一个需要在 pl/python 中重写上述查询的数据集吗?
- 您是否看到这种查询在 O(K log n) 中不起作用的任何情况?