問題タブ [query-planner]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
postgresql - テーブル内の異なるデータが異なるパフォーマンスで処理されるのはなぜですか?
Postgres 10 データベースで奇妙なパフォーマンスの問題が発生しています。
私はそのようなテーブルを持っています:
このテーブルにアクセスするための Python lib (psycopg2 ドライバーを使用) があります。テーブルに対して単純なクエリを実行します。そのうちの 1 つはコンテンツの一括ダウンロードに使用され、次のようになります。
一部の ID ではかなり高速に動作するのに対し、他の ID では 4 ~ 5 倍遅いことに気付きました。このテーブルには、ID の 2 つの主要な「カテゴリ」があることに注意してください。1 つ目は 2 億 7000 万から 5 億の範囲で、2 つ目は 100 億から 1000 3000 万の範囲です。最初の範囲では「高速」、2 番目の範囲では「低速」です。int
より大きな絶対数が からそれらを引き出すことに加えbigint
て、2 番目の範囲の値はより「まばら」です。つまり、最初の範囲の値はほとんど帰結的 (欠損値の「穴」がほとんどない) ですが、2 番目の範囲でははるかに多くの値があります。 「穴」 (平均充填率は 30%)。
他のライブラリの影響を排除するために、次のクエリを使用して合成テストを実施しました。
要求されたチャックの長さを調整して、要求ごとの JSONB の要約の長さを平均的に等しくしました。
さらに、返された処理速度をcount(*)
実行時間で割って計算します。最初の範囲は 800 ~ 1050 行/秒、2 番目の範囲は 120 ~ 250 行/秒です。もう 1 つのメトリックは、1 時間あたりの処理された JSON の長さです。クエリの主な問題は JSONB データの処理であるように見えるので、どちらの場合も平均的に同じであるに違いないと思います。しかし違います: 7-10 MB/s 対 1.5-2.5 MB/s です。
そのため、問題が再現されました。絶対値では高速になりましたが (ネットワーク転送がないため)、パフォーマンスの大きな違いは持続します。両方の範囲でクエリの実行プランを比較しましたが、同等に見えます ( EXPLAIN ANALYZE
):
私が見る唯一の違いはbigint
、1回限りの変換です。
何か不足していますか?それを調査(および修正)する方法は?
更新 1:EXPLAIN
で追加BUFFERS
:
更新 2:その他の実験:
テーブル内のすべてのデータに対して上記のアプローチを活用するために、さらにいくつかのテストを実施しました。簡単なプログラムを使用して、セグメントの境界を繰り返し処理し、最終的に両方の範囲のすべてのデータを処理します。この間、EXPLAIN ANALYZE の結果を解析し、次の一連のメトリックを収集します。
- テーブルのバッファ ヒット/読み取り。
- インデックスのバッファ ヒット/読み取り。
- 行数 (から
Index Scan...
) - 実行期間
上記のメトリックに基づいて、継承されたメトリックを計算します。
- ディスク読み取り率: (インデックス読み取り + テーブル読み取り) * 8192 / 期間。
- 読み取り率: (インデックス読み取り + テーブル読み取り) / (インデックス読み取り + テーブル読み取り + インデックス ヒット + テーブル ヒット)
- データ レート: (インデックス読み取り + テーブル読み取り + インデックス ヒット + テーブル ヒット) * 8192 / 期間
ID の「密度」は「小さい」範囲と「大きい」範囲で異なるため、どちらの場合も反復ごとに約 5000 行になるようにチャンクのサイズを調整しましたが、私の実験では、チャンク サイズはそれほど重要ではないことが示されています。 .
上記の結果は、 1 番目と 2 番目の範囲全体で確認されました(したがって、ランダムにキャッシュされたデータだけが原因ではありませんでした)。
キャッシュの影響を排除するために、バッファをフラッシュして Postgres サーバーを再起動しました。
この後、テストを繰り返し、ほぼ同じ写真を取得しました。
前回のテストのシリーズをチャートにレンダリングし、ここに投稿しました。
これは「小さい」範囲の写真です。ディスクの読み取り速度は、テスト全体で一様に約 10 ~ 11 MB/秒です。
質問: メモリー・バッファーをフラッシュしたのに、ヒット率が非常に高い (読み取り率が低い) のはなぜですか?
これは「大きい」範囲の写真です。それは私には非常識に見えます。ほとんどの場合、ディスクの読み取り速度は約 2 MB/秒でしたが、26 ~ 30 MB/秒に跳ね上がることもありました。読み取り率も大きく異なります。
テスト中にディスクの読み取り速度を検証したiotop
ところ、その表示が私が計算したものに非常に近いことがわかりました。ずっと監視していたとは言えませんが、第2レンジで2MB/sと22MB/s、第1レンジで10MB/sのときに確認しました。htop
また、CPU がボトルネックではなく、テスト中に約 3% であることも確認しました。
この問題は、マスター サーバーとスレーブ サーバーの両方で再現可能です。私のテストはスレーブで実施されましたが、DBMS に他の負荷がかかったり、DBMS に関係のないホストでディスク アクティビティが発生したりすることはありませんでした。
私の唯一の仮定は、仮想化または何かのために、データのさまざまなフラグメントがさまざまな速度で読み取られているということですが...なぜこれらの範囲に厳密にバインドされているのですか? 2 つの異なるマシンで同じになるのはなぜですか?
何か案は?
sql - OR 内にネストされた複数の AND 条件を使用して SQL にインデックスを付ける方法
次の sql を高速化したい (コストは 19685.75)。複数の複雑なネストされた AND 条件が WHERE ステートメントで OR と組み合わされているこの SQL にインデックスを付けることはできますか?
テーブル テキストには、次のフィールドとインデックスが含まれています (他のフィールドは表示されていません)。
created_at、lastmod、publication_date の 3 つの単一インデックスを追加しました。これらのフィールドの 1 つの複数列インデックス。
しかし、postgres EXPAIN クエリでは、この where 句はまだSeq Scanを使用していますが、 Index Scanは使用していません。
私の質問は次のとおり
です。1. この複雑な SELECT 句にインデックス スキャンを使用するように postgres を作成することは可能ですか?
2. AND 句ごとに 1 つの複数列インデックスを作成する必要がありますか? たとえば(publication_date, lastmod)
、この原因でインデックスを作成しますか?
- インデックスは IS NULL の検索で機能しますか? IS NULL のフィールド検索はインデックスにする必要がありますか?
2018 年 11 月 4 日更新
フィールドを 1 つずつテストしてクエリを最小化しようとすると、フィールドpublication_date
とlast_mod
トリガー インデックス スキャンが個別に行われますが、次のcreated_at
ことはできません。
created_at
タイムスタンプだからですか?しかし、タイムスタンプのインデックスが機能しないのはなぜですか?
publication_date
トリガーインデックススキャンのようです: