PostgreSQL 9.5:新機能 パート2. TABLESAMPLE

PostgreSQL 9.5の革新を引き続き確認します。

パート1.衝突しないでください/更新と行レベルのセキュリティ

パート3.グループ化セット、キューブ、ロールアップ

著者から
第二部のリリースが遅れたことをおaび申し上げます。 最初は、最初の記事の1週間後に記事の2番目の部分をリリースする予定でしたが、作業負荷が高いため、これを行うことができませんでした。 したがって、私は大きな記事ではなく、小さな部分で、より頻繁に発行することにしました。


テーブルからいくつかのランダムエントリを選択する必要があるタスクがある場合があります。このために、洗練されたクエリを作成しました(本当にランダムなデータを取得するために、たくさん汗をかく必要があります)。 PostgreSQL 9.5のリリースにより、このタスクはより簡単になります。

TABLESAMPLEキーワードを使用すると、テーブルからすべてのデータを選択することはできませんが、サンプルの一部を選択することができます。

構文は次のようになります。



SELECT ... FROM TABLE_NAME ... TABLESAMPLE sampling_method argument [ ... ] [ REPEATABLE seed ]


sampling_methodはサンプリングメソッドであり、PostgreSQL 9.5ではデフォルトでSYSTEMBERNOULLIの 2つがあります。これらは引数として浮動小数点数(または数値を生成する有効な式)を取り、サンプリングのパーセンテージとして解釈されます:0から100まで。



PostgreSQL 9.5でサンプリングがどのように機能するかの例を見てみましょう。

トランザクションID、トランザクション量、およびトランザクションが完了した日付と時刻が保存されているトランザクションを含むテーブルがあるとします。 テーブルに100,000エントリを追加します。



CREATE TABLEトランザクション

idシリアルプライマリ キー

NUMERIC 15、2

ending_time TIMESTAMP

;



INSERT INTOトランザクション amount ending_time

選択

ラウンド CAST random * 100000 AS NUMERIC 2 ))

now - random * CAST '1 day' AS INTERVAL

FROM generate_series 1、100000 ;



元のテーブル(100レコード)から0.1%のレコードのサンプルを取得してみましょう。

SELECT * FROMトランザクションTABLESAMPLE SYSTEM 0.1



合計クエリランタイム: 213ミリ秒

157行が取得されました


なぜ100レコードを取得できなかったのに157 事実、PostgreSQL はテーブルデータを8 kbページの配列の形式で保存し (デフォルトでは、ソースコードからサーバーを構築するときにこのパラメーターを変更できます)、サンプリングメソッドSYSTEMを使用すると、指定されたパーセント数のランダムページ数を取得し、 「そのままです。」 この場合、157エントリが1ページに配置されます。 サンプルに対して2倍のレコードを要求すると、2ページのデータが取得されます。

SELECT * FROMトランザクションTABLESAMPLE SYSTEM 0.2



合計クエリランタイム: 21ミリ秒

314行が取得されました


異なるページには異なる数のレコードを格納できるため、返されるレコードの数はリクエストごとに異なる可能性があることを理解してください。

レコードの正確な数を取得するには、 LIMIT式を使用できますが、この場合はいずれにしても、1ページからレコードを取得することを理解する価値があります。 したがって、レコードの値がこれらのレコードが挿入された順序に依存している場合、またはレコード自体の値の性質が時系列である場合(この場合、ending_timeフィールドの場合のように)、サンプルを作成することで無意味な結果が得られる可能性が高くなります。 たとえば、サンプルを介してトランザクションが行われた最大日付を調べて、同じリクエストを数回行うと、まったく異なる結果が得られます。

SELECT MAX ending_time FROMトランザクションTABLESAMPLE SYSTEM 0.1


最大
2014-11-08 22:30:32.720855


SELECT MAX ending_time FROMトランザクションTABLESAMPLE SYSTEM 0.1


最大
2014-12-02 11:42:32.720855


SELECT MAX ending_time FROMトランザクションTABLESAMPLE SYSTEM 0.1


最大
2014-10-21 09:40:32.720855


実際の値は次のとおりです。

SELECT MAX ending_time FROMトランザクション


最大
2014-12-07 04:04:32.720855


より分散されたサンプルを取得するには、 BERNOULLIサンプリングメソッドを使用して、テーブル全体をスキャンし(実際、各レコードについて「コインを投げる」)、ランダムなレコードを選択します。

SELECT MAX ending_time FROMトランザクションTABLESAMPLE BERNOULLI 0.1


最大
2014-12-07 00:06:32.720855


次に、パフォーマンスを見て、3つの方法で平均取引額の受領を分析し、平均自体を取得してみましょう。



1)サンプルなし:

EXPLAIN ANALYZE SELECT AVG amount from transaction

「集計(コスト= 1887.00..1887.01行= 1幅= 8)(実際の時間= 25.795..25.795行= 1ループ= 1)」

「->トランザクションのシーケンススキャン(コスト= 0.00..1637.00行= 100000幅= 8)(実際の時間= 0.005..12.438行= 100000ループ= 1)」

「計画時間:0.055ミリ秒」

「実行時間:25.816ミリ秒」



トランザクションからSELECT AVG 金額

50028.8742828


2) SYSTEMメソッドによるサンプル:

EXPLAIN ANALYZE SELECT AVG amount from transaction TABLESAMPLE SYSTEM 0.1

「集計(コスト= 1.25..1.26行= 1幅= 8)(実際の時間= 0.088..0.088行= 1ループ= 1)」

「->トランザクションのサンプルスキャン(システム)(コスト= 0.00..1.00行= 100幅= 8)(実際の時間= 0.017..0.048行= 157ループ= 1)」

「計画時間:0.068ミリ秒」

「実行時間:0.120 ms」



トランザクションTABLESAMPLEシステムからのAVG 金額)の 選択 0.1

53628.223694267516


3) BERNOULLIサンプル

EXPLAIN ANALYZE SELECT AVG amount from transaction TABLESAMPLE BERNOULLI 0.1

「集計(コスト= 638.25..638.26行= 1幅= 8)(実際の時間= 2.847..2.847行= 1ループ= 1)」

「->トランザクションのサンプルスキャン(bernoulli)(コスト= 0.00..638.00行= 100幅= 8)(実際の時間= 0.020..2.780行= 104ループ= 1)」

「計画時間:0.145ミリ秒」

「実行時間:2.872ミリ秒」



トランザクションからのAVG 金額)の 選択 TABLESAMPLE BERNOULLI 0.1

50285.863240740741


SYSTEMメソッドを使用したサンプリングは高速ですが、同時にその精度は低く、 BERNOULLIメソッドによるサンプリングは低速ですが、精度は高いことがわかります。 速度と精度の間で妥協点を選択できます。 また、サンプリングには新しいタイプのスキャン(サンプルスキャン)が使用されることに注意してください。

テーブルにさらにレコードを追加し、2,000万件のレコードを追加します。

INSERT INTOトランザクション amount ending_time

選択

ラウンド CAST random * 100000 AS DECIMAL 2 ))

- 間隔 '1年' + i * 間隔 '1分'

FROM generate_series 100001、20000000 i;



EXPLAIN ANALYZE SELECT AVG amount from transaction;



「集計(コスト= 377372.70..377372.71行= 1幅= 8)(実際の時間= 4604.297..4604.297行= 1ループ= 1)」

"->トランザクションのシーケンススキャン(コスト= 0.00..327375.96行= 19998696幅= 8)(実際の時間= 0.027..2043.846行= 20,000,000ループ= 1)"

「計画時間:0.063ミリ秒」

「実行時間:4604.325 ms」



SELECT AVG amount FROM transaction;

50002.888681451



EXPLAIN ANALYZE SELECT AVG amount from transaction TABLESAMPLE SYSTEM 0.1

「集計(コスト= 757.99..758.00行= 1幅= 8)(実際の時間= 7.309..7.309行= 1ループ= 1)」

「->トランザクションのサンプルスキャン(システム)(コスト= 0.00..707.99行= 19999幅= 8)(実際の時間= 0.057..4.588行= 20096ループ= 1)」

「計画時間:0.073ミリ秒」

「実行時間:7.340ミリ秒」

トランザクションTABLESAMPLEシステムからのAVG 金額)の 選択 0.1

50323.198322551752



EXPLAIN ANALYZE SELECT AVG amount from transaction TABLESAMPLE BERNOULLI 0.1

「集計(コスト= 127638.99..127639.00行= 1幅= 8)(実際の時間= 751.831..751.832行= 1ループ= 1)」

「->トランザクションのサンプルスキャン(bernoulli)(コスト= 0.00..127588.99行= 19999幅= 8)(実際の時間= 0.260..747.682行= 19899ループ= 1)」

「計画時間:0.055ミリ秒」

「実行時間:751.879ミリ秒」



トランザクションからのAVG 金額)の 選択 TABLESAMPLE BERNOULLI 0.1

50043.386386377336


レコード数が増えると、 BERNOULLIメソッドのパフォーマンスが低下することがわかります。 これは、実際には全テーブルスキャンを実行するのに対し、 SYSTEMは数ページを返すだけだからです。



次に、レコードを選択する割合を増やしてみましょう。

EXPLAIN ANALYZE SELECT AVG amount from transaction TABLESAMPLE SYSTEM 1

「集計(コスト= 7591.84..7591.85行= 1幅= 8)(実際の時間= 65.055..65.055行= 1ループ= 1)」

「->トランザクションのサンプルスキャン(システム)(コスト= 0.00..7091.87行= 199987幅= 8)(実際の時間= 0.043..37.939行= 200018ループ= 1)」

「計画時間:0.053ミリ秒」

「実行時間:65.083ミリ秒」



EXPLAIN ANALYZE SELECT AVG amount from transaction TABLESAMPLE BERNOULLI 1

「集計(コスト= 129888.84..129888.85行= 1幅= 8)(実際の時間= 799.826..799.826行= 1ループ= 1)」

「->トランザクションのサンプルスキャン(bernoulli)(コスト= 0.00..129388.87行= 199987幅= 8)(実際の時間= 0.035..769.899行= 199682ループ= 1)」

「計画時間:0.063ミリ秒」

「実行時間:799.859ミリ秒」


ご覧のとおり、 SYSTEMメソッドは、サンプルの割合を増やすとパフォーマンスが低下します。 これは論理的です。BERNOULLIはフルスキャンと同じように動作し、 SYSTEMは10倍のページを返す必要があるためです。

その結果、サンプルのごく一部のSYSTEMメソッドはBERNOULLIよりもはるかに高速に動作しますが、同時にレコードのランダムな選択が少なくなることに注意できます。 しかし、関心が高まると、この利点は失われます。



オプションのREPEATABLEキーワードを使用して、ランダムジェネレーターのシードを指定できます。 2つのクエリのサンプリング方法、サンプリングの割合、およびseedが同じ場合、これらの2つのクエリに対して同じサンプルが選択されます。

トランザクションテーブルサンプルシステムからのMAX 金額)の 選択 0.1 繰り返し可能 50

99997.91



トランザクションテーブルサンプルシステムからのMAX 金額)の 選択 0.1 繰り返し可能 300

99999.15



トランザクションからのMAX 金額)の 選択 TABLESAMPLE BERNOULLI 0.1 繰り返し可能 50

99995.9



トランザクションテーブルサンプルシステムからのMAX 金額)の 選択 0.1 繰り返し可能 50

99997.91


上で見たように、 REPEATABLEキーワードが指定されていない場合、毎回選択が前のものと異なります。



これとは別に、 WHERE句の前にサンプリングが実行されることに注意してください。つまり、条件によってサンプルを選択することはできません。 この場合、サンプルが最初に選択され、次にWHERE条件が適用されますが、20,000,000レコードのテーブルからid <100のレコードを取得する確率は非常に小さいため、結果は空になります。

SELECT * FROMトランザクションTABLESAMPLE SYSTEM 1 WHERE id < 100

合計クエリランタイム: 31ミリ秒

0行が取得されました


SYSTEMBERNOULLIだけがサンプリングオプションではありません。必要に応じて、独自のサンプリング方法を作成できます。 このドキュメントはこちらにあります 。 さらに、カスタムサンプリングメソッドは、複数の引数をとるか、まったくとらない場合があります。 カスタムメソッドは、 REPEATABLEキーワードも無視する場合があります。



これで、PostgreSQL 9.5でのサンプリングに関する短い話は終わりです。 ご清聴ありがとうございました!



PSサンプルを使用して、テーブル内のレコード数を概算できます:)

SELECT COUNT * * 100.0 FROMトランザクションTABLESAMPLE SYSTEM 1 ;

20001800


PPS上記のようにしないでください。これは冗談であり、常に正常に機能するとは限りません。

次の部分: GROUPINS SETS、ROLLUP、CUBE



All Articles