複数の「間」条件でクエリを最適化する

Georgy Savva

playground列のあるテーブルがありval、列valにインデックスが付けられています。

範囲のリストがあり[(min1, max1), (min2, max2), ... , (minN, maxN)]valそれらの範囲のいずれかに適合するすべての行を選択したいと思います。

たとえば、私の範囲は次のようになり[(1,5), (20,25), (200,400)]ます。対応する行を抽出する簡単なクエリは次のとおりです。

select p.*
from playground p
where (val between 1 AND 5) or (val between 20 and 25) or
    (val between 200 and 400);

ここでの問題は、この範囲のリストが動的であるということです。私のアプリケーションはそれを生成し、クエリと一緒にpostgresに送信します。

範囲の動的リストを受け入れるようにクエリを書き直そうとしました。

select p.*
from playground p,
    unnest(ARRAY [(1, 5),(20, 25),(200, 400)]) as r(min_val INT, max_val INT)
where p.val between r.min_val and r.max_val;

同じ行を抽出しますが、効果的なクエリかどうかわかりませんか?

これは、最初のクエリの説明がどのように見えるかです。

Bitmap Heap Scan on playground p  (cost=12.43..16.45 rows=1 width=36) (actual time=0.017..0.018 rows=4 loops=1)
  Recheck Cond: (((val >= 1) AND (val <= 5)) OR ((val >= 20) AND (val <= 25)) OR ((val >= 200) AND (val <= 400)))
  Heap Blocks: exact=1
  ->  BitmapOr  (cost=12.43..12.43 rows=1 width=0) (actual time=0.012..0.012 rows=0 loops=1)
        ->  Bitmap Index Scan on playground_val_index  (cost=0.00..4.14 rows=1 width=0) (actual time=0.010..0.010 rows=3 loops=1)
              Index Cond: ((val >= 1) AND (val <= 5))
        ->  Bitmap Index Scan on playground_val_index  (cost=0.00..4.14 rows=1 width=0) (actual time=0.001..0.001 rows=0 loops=1)
              Index Cond: ((val >= 20) AND (val <= 25))
        ->  Bitmap Index Scan on playground_val_index  (cost=0.00..4.14 rows=1 width=0) (actual time=0.001..0.001 rows=1 loops=1)
              Index Cond: ((val >= 200) AND (val <= 400))
Planning Time: 0.071 ms
Execution Time: 0.057 ms

そしてここに2番目の説明があります:

Nested Loop  (cost=0.14..12.52 rows=2 width=36) (actual time=0.033..0.065 rows=4 loops=1)
  ->  Function Scan on unnest r  (cost=0.00..0.03 rows=3 width=8) (actual time=0.011..0.012 rows=3 loops=1)
  ->  Index Scan using playground_val_index on playground p  (cost=0.13..4.15 rows=1 width=36) (actual time=0.008..0.015 rows=1 loops=3)
        Index Cond: ((val >= r.min_val) AND (val <= r.max_val))
Planning Time: 0.148 ms
Execution Time: 0.714 ms

注:どちらの場合もset enable_seqscan = false;、インデックスを機能させるために行いました。

「ネステッドループ」のステージが気になります。大丈夫ですか?または、範囲の動的リストをクエリに渡すためのより効果的な方法はありますか?私のpostgresバージョンは12.1

アーウィンブランドステッター

あなたはより多くの情報を追加しましたが、まだはるかに関連性があります。正確なテーブルとインデックスの定義、カーディナリティ、データ分布、行サイズの統計、述語の範囲の数、テーブルの目的、書き込みパターンなど。パフォーマンスの最適化には、取得できるすべての入力が必要です。

暗闇での撮影:範囲が重複しない場合UNION ALLクエリ最高のパフォーマンスを発揮する可能性があります

SELECT * FROM playground WHERE val BETWEEN   1 AND   5
UNION ALL
SELECT * FROM playground WHERE val BETWEEN  20 AND  25
UNION ALL
SELECT * FROM playground WHERE val BETWEEN 200 AND 400;

私たちは知っている範囲が重複しないように、それはあなたの試みに余分な作業を行う必要がありますので、Postgresは、しません。このクエリはBitmapOr、最初のNested Loop計画と2番目の計画の両方を回避する必要があります各範囲をフェッチして、出力に追加するだけです。次のような計画になります。

Append  (cost=0.13..24.50 rows=3 width=40)
  ->  Index Scan using playground_val_idx on playground  (cost=0.13..8.15 rows=1 width=40)
        Index Cond: ((val >= 1) AND (val <= 5))
  ->  Index Scan using playground_val_idx on playground playground_1  (cost=0.13..8.15 rows=1 width=40)
        Index Cond: ((val >= 20) AND (val <= 25))
  ->  Index Scan using playground_val_idx on playground playground_2  (cost=0.13..8.15 rows=1 width=40)
        Index Cond: ((val >= 200) AND (val <= 400))

さらに、各サブSELECTは、範囲のリストが長い場合でも、一般的な推定値ではなく、特定の範囲の実際の統計に基づいています。参照(推奨!):

クライアントでクエリを生成するか、サーバー側の関数を記述して動的SQLを生成および実行できます(結果の種類がわかっている場合に適用可能)。

LOOP(多くの場合効率が低下しますが、これは例外である可能性があります)を使用してサーバー側関数をテストすることもできます。

CREATE OR REPLACE FUNCTION foo(_ranges int[])
  RETURNS SETOF playground LANGUAGE plpgsql PARALLEL SAFE STABLE AS
$func$
DECLARE
   _range   int[];
BEGIN
   FOREACH _range SLICE 1 IN ARRAY _ranges
   LOOP
      RETURN QUERY
      SELECT * FROM playground WHERE val BETWEEN _range[1] AND _range[2];
   END LOOP;
END
$func$;

オーバーヘッドは、通話のいくつかの範囲に対して支払われない場合があります。しかし、他に何もないとしても、呼び出すのは非常に便利です。

SELECT * FROM foo('{{1,5},{20,25},{200,400}}');

関連:

db <>フィドルはこちら

行の物理的な順序が大いに役立つ場合があります行が順番に格納されている場合、処理する必要のあるデータページは(はるかに)少なくなります。未公開の詳細に依存します。ビルトインCLUSTERまたは拡張機能pg_repackまたはそれpg_squeezeを助けるかもしれません。関連:

また、使用中のメジャーバージョンには、利用可能な最新のマイナーリリースを使用することをお勧めします。これを書いている時点では12.2になります(2020-02-13リリース)。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Sparkで複数のJDBCクエリを最適化する

分類Dev

複数の同様の条件を持つクエリを最適化する方法

分類Dev

MySQLは複数条件クエリを選択するのが最適です

分類Dev

複数選択でSQLクエリを最適化する方法

分類Dev

複数のテーブルでクエリを最適化する

分類Dev

複数の検索条件に対する検索クエリの最適化

分類Dev

複数の合計でクエリを最適化しますか?

分類Dev

複数の左結合SQLSELECTクエリを最適化する方法は?

分類Dev

複数の列/マルチインデックスでパンダクエリを最適化する

分類Dev

Redshiftクエリの大きなIN条件を最適化する

分類Dev

複数の最小範囲と最大範囲でSQLクエリを最適化する

分類Dev

複数のCASEステートメントでSELECTクエリを最適化する方法は?

分類Dev

この複雑なクエリを最適化する方法は?

分類Dev

この複雑なクエリを最適化する方法は?

分類Dev

SQLiteはWHERE句に複数のAND条件を使用してクエリを最適化しますか?

分類Dev

複数のselectクエリを使用してUNIONmysqlクエリを最適化する方法は?

分類Dev

重複するクエリを排除するdjangoでのクエリの最適化

分類Dev

SQLクエリの数を最適化する

分類Dev

Postgres:複数のjson_array_elements()呼び出しを使用するこのクエリを最適化する方法

分類Dev

複数の行数サブクエリを結合するビューのスキーマを最適化する

分類Dev

一定期間のアイテム数を取得するSQLクエリを最適化する

分類Dev

複数のファイルの出力タイプスクリプトでモジュールの名前空間を最適化する方法、gulpを使用する

分類Dev

ActiveRecordRailsを使用した複数のクエリの最適化

分類Dev

複数のテーブルを結合するクエリでMySQLの「OrderByLimit1」を最適化するにはどうすればよいですか?

分類Dev

この mysql クエリ (更新、複数の結合) を最適化する方法はありますか?

分類Dev

2つの選択でSQLクエリを最適化する

分類Dev

CreateViewでRANKベースのクエリを最適化する

分類Dev

MySQL:3つの結合でクエリを最適化する

分類Dev

Laravelのデータベースから複数の値のクエリを最適化する方法

Related 関連記事

  1. 1

    Sparkで複数のJDBCクエリを最適化する

  2. 2

    複数の同様の条件を持つクエリを最適化する方法

  3. 3

    MySQLは複数条件クエリを選択するのが最適です

  4. 4

    複数選択でSQLクエリを最適化する方法

  5. 5

    複数のテーブルでクエリを最適化する

  6. 6

    複数の検索条件に対する検索クエリの最適化

  7. 7

    複数の合計でクエリを最適化しますか?

  8. 8

    複数の左結合SQLSELECTクエリを最適化する方法は?

  9. 9

    複数の列/マルチインデックスでパンダクエリを最適化する

  10. 10

    Redshiftクエリの大きなIN条件を最適化する

  11. 11

    複数の最小範囲と最大範囲でSQLクエリを最適化する

  12. 12

    複数のCASEステートメントでSELECTクエリを最適化する方法は?

  13. 13

    この複雑なクエリを最適化する方法は?

  14. 14

    この複雑なクエリを最適化する方法は?

  15. 15

    SQLiteはWHERE句に複数のAND条件を使用してクエリを最適化しますか?

  16. 16

    複数のselectクエリを使用してUNIONmysqlクエリを最適化する方法は?

  17. 17

    重複するクエリを排除するdjangoでのクエリの最適化

  18. 18

    SQLクエリの数を最適化する

  19. 19

    Postgres:複数のjson_array_elements()呼び出しを使用するこのクエリを最適化する方法

  20. 20

    複数の行数サブクエリを結合するビューのスキーマを最適化する

  21. 21

    一定期間のアイテム数を取得するSQLクエリを最適化する

  22. 22

    複数のファイルの出力タイプスクリプトでモジュールの名前空間を最適化する方法、gulpを使用する

  23. 23

    ActiveRecordRailsを使用した複数のクエリの最適化

  24. 24

    複数のテーブルを結合するクエリでMySQLの「OrderByLimit1」を最適化するにはどうすればよいですか?

  25. 25

    この mysql クエリ (更新、複数の結合) を最適化する方法はありますか?

  26. 26

    2つの選択でSQLクエリを最適化する

  27. 27

    CreateViewでRANKベースのクエリを最適化する

  28. 28

    MySQL:3つの結合でクエリを最適化する

  29. 29

    Laravelのデータベースから複数の値のクエリを最適化する方法

ホットタグ

アーカイブ