私はHadoop:TomWhiteによる決定的なガイドを読んでいます。13.6章「HBasevsRDMS」で、データが多い場合、最近の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;
(各クエリの「LIMIT10」に注意してください。ところで、ユニオンを制限して順序付けすることはできませんが、読みやすくするためにラッピング選択を削除しました)
各サブクエリは、インデックスO(logN)で正しい位置を見つけ、10個のアイテムを返すのと同じ速さで実行する必要があります。そのK回繰り返すと、O(KlogN)が得られます。
また、クエリプランナーがひどくて最初のクエリを最適化できない場合でも、pl / pythonで何も記述せずに、いつでもそれをユニオン付きのクエリに変換して、目的のパフォーマンスを得ることができます。
計算を再確認するために、9,000,000のテストレコードで満たされた1つのpostgresqlの上でクエリを実行しました。結果は、両方のクエリが最初のクエリで100ミリ秒、2番目のクエリ(ユニオンのあるクエリ)で300ミリ秒と非常に高速であるという私の期待を裏付けました。
したがって、クエリが9,000,000(logn = 23)のレコードに対して100msで実行される場合、9,000,000,000(logn = 33)のレコードに対しては140msで実行されるはずです。
質問
- 上記の推論に欠陥がありますか?
- 上記のようなクエリをpl/pythonで書き直す必要があるデータセットを想像できますか?
- そのようなクエリがO(K log n)で機能しない状況はありますか?