我正在阅读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,但查询规划器实际上实现了整个合并,然后在最后限制.....实际上我们写了一个执行heapsort的自定义PL/Python脚本....几乎在所有情况下,这都优于本机SQL实现和查询规划器的策略......
预期的穿孔和expermiental结果
我无法想象会导致此类问题的数据集,您必须编写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;
(请注意每个查询中的"限制10".顺便说一句,我知道我不能限制和订购工会,但为了便于阅读,我已经删除了包装选项)
每个子查询的运行速度应该与在索引O(logN)中找到正确的位置并返回10个项目一样快.如果我们重复K次,我们得到O(KlogN).
即使查询规划器如此糟糕以至于它无法优化第一个查询,我们总是可以将它转换为带有联合的查询并获得所需的性能而无需在pl/python中编写任何内容.
为了仔细检查我的计算,我运行了一个postgresql上面的查询,其中填充了9,000,000个测试记录.结果证实了我的期望,对于第一个查询,两个查询都非常快100毫秒,第二个查询是300毫秒(具有联合的查询).
因此,如果查询在100毫秒内运行9,000,000(logn = 23)个记录,那么对于9,000,000,000(logn = 33)个记录,它应该在140毫秒内运行.
问题
你认为上述推理存在任何缺陷吗?
您能想象一下您需要在pl/python中重写上述查询的数据集吗?
你看到这种查询在O(K log n)中不起作用的情况吗?
araqnid.. 6
他们声称RDMBS查询规划器将该解决方案用于查询是不正确的,至少对于Postgresql 9.0而言,我应该想象其他平台.我用类似的查询进行了快速测试:
explain select * from client_attribute where client_attribute_type_code in ('UAG', 'RFR', 'IPA', 'FVD') order by client_attribute_id desc limit 10; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------- Limit (cost=0.00..0.93 rows=10 width=85) -> Index Scan Backward using client_attribute_pkey on client_attribute (cost=0.00..15516.47 rows=167234 width=85) Filter: (client_attribute_type_code = ANY ('{UAG,RFR,IPA,FVD}'::bpchar[])) (3 rows)
这里client_attribute_id被索引,因此它完全按照需要 - 遍历索引,应用过滤器并在输出达到限制时停止.
如果未对订购列编制索引,则需要进行表扫描和排序,但只扫描一个表:
explain analyze select * from client_attribute where client_attribute_type_code in ('UAG', 'RFR', 'IPA', 'FVD') order by updated desc limit 10; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=13647.00..13647.03 rows=10 width=85) (actual time=180.961..180.964 rows=10 loops=1) -> Sort (cost=13647.00..14065.09 rows=167234 width=85) (actual time=180.960..180.961 rows=10 loops=1) Sort Key: updated Sort Method: top-N heapsort Memory: 26kB -> Seq Scan on client_attribute (cost=0.00..10033.14 rows=167234 width=85) (actual time=0.010..106.791 rows=208325 loops=1) Filter: (client_attribute_type_code = ANY ('{UAG,RFR,IPA,FVD}'::bpchar[]))
这使用了一个heapsort来保持顺序扫描过程中的前10个结果,这听起来就像他们自己写的解决方案.
他们声称RDMBS查询规划器将该解决方案用于查询是不正确的,至少对于Postgresql 9.0而言,我应该想象其他平台.我用类似的查询进行了快速测试:
explain select * from client_attribute where client_attribute_type_code in ('UAG', 'RFR', 'IPA', 'FVD') order by client_attribute_id desc limit 10; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------- Limit (cost=0.00..0.93 rows=10 width=85) -> Index Scan Backward using client_attribute_pkey on client_attribute (cost=0.00..15516.47 rows=167234 width=85) Filter: (client_attribute_type_code = ANY ('{UAG,RFR,IPA,FVD}'::bpchar[])) (3 rows)
这里client_attribute_id被索引,因此它完全按照需要 - 遍历索引,应用过滤器并在输出达到限制时停止.
如果未对订购列编制索引,则需要进行表扫描和排序,但只扫描一个表:
explain analyze select * from client_attribute where client_attribute_type_code in ('UAG', 'RFR', 'IPA', 'FVD') order by updated desc limit 10; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------- Limit (cost=13647.00..13647.03 rows=10 width=85) (actual time=180.961..180.964 rows=10 loops=1) -> Sort (cost=13647.00..14065.09 rows=167234 width=85) (actual time=180.960..180.961 rows=10 loops=1) Sort Key: updated Sort Method: top-N heapsort Memory: 26kB -> Seq Scan on client_attribute (cost=0.00..10033.14 rows=167234 width=85) (actual time=0.010..106.791 rows=208325 loops=1) Filter: (client_attribute_type_code = ANY ('{UAG,RFR,IPA,FVD}'::bpchar[]))
这使用了一个heapsort来保持顺序扫描过程中的前10个结果,这听起来就像他们自己写的解决方案.