11

簡単なクエリと 2 つのテーブルがあります。

drilldown

CREATE SEQUENCE drilldown_id_seq;

CREATE TABLE drilldown (
    transactionid bigint NOT NULL DEFAULT nextval('drilldown_id_seq'),
    userid bigint NOT NULL default 0 REFERENCES users(id),
    pathid bigint NOT NULL default 0,
    reqms bigint NOT NULL default 0,
    quems bigint NOT NULL default 0,
    clicktime timestamp default current_timestamp,
    PRIMARY KEY(transactionid)
);

ALTER SEQUENCE drilldown_id_seq OWNED BY drilldown.transactionid;

CREATE INDEX drilldown_idx1 ON drilldown (clicktime);

querystats

CREATE SEQUENCE querystats_id_seq;

CREATE TABLE querystats (
    id bigint NOT NULL DEFAULT nextval('querystats_id_seq'),
    transactionid bigint NOT NULL default 0 REFERENCES drilldown(transactionid),
    querynameid bigint NOT NULL default 0 REFERENCES queryname(id),
    queryms bigint NOT NULL default 0,
    PRIMARY KEY(id)
);

ALTER SEQUENCE querystats_id_seq OWNED BY querystats.id;

CREATE INDEX querystats_idx1 ON querystats (transactionid);
CREATE INDEX querystats_idx2 ON querystats (querynameid);

drilldown150 万件のレコードがあり、querystats1,000 万件のレコードがあります。問題は、2 つを結合するときに発生します。

クエリ

explain analyse
select avg(qs.queryms)
  from querystats qs
  join drilldown d on (qs.transactionid=d.transactionid)
  where querynameid=1;

クエリプラン

集計 (コスト=528596.96..528596.97 行=1 幅=8) (実際の時間=5213.154..5213.154 行=1 ループ=1)
   -> ハッシュ結合 (コスト = 274072.53..518367.59 行 = 4091746 幅 = 8) (実際の時間 = 844.087..3528.788 行 = 4117717 ループ = 1)
         ハッシュ条件: (qs.transactionid = d.transactionid)
         -> querystats qs でのビットマップ ヒープ スキャン (コスト = 88732.62..210990.44 行 = 4091746 幅 = 16) (実際の時間 = 309.502..1321.029 行 = 4117717 ループ = 1)
               条件を再確認してください: (querynameid = 1)
               -> querystats_idx2 でのビットマップ インデックス スキャン (コスト=0.00..87709.68 行=4091746 幅=0) (実際の時間=307.916..307.916 行=4117718 ループ=1)
                     索引条件: (querynameid = 1)
         -> ハッシュ (コスト=162842.29..162842.29 行=1371250 幅=8) (実際の時間=534.065..534.065 行=1372574 ループ=1)
               バケット: 4096 バッチ: 64 メモリ使用量: 850kB
               -> ドリルダウン d で drilldown_pkey を使用したインデックス スキャン (コスト=0.00..162842.29 行=1371250 幅=8) (実際の時間=0.015..364.657 行=1372574 ループ=1)
 総実行時間: 5213.205 ミリ秒
(11行)

PostgreSQL 用に調整できるチューニング パラメータがいくつかあることは知っていますが、知りたいのは、2 つのテーブルを結合する最適な方法で実行しているクエリです。

それとも、ある種のINNER JOINですか?よくわかりません。

どんなポインタでも大歓迎です!

編集

database#\d drilldown
                                       Table "public.drilldown"
    Column     |            Type             |                       Modifiers                        
---------------+-----------------------------+--------------------------------------------------------
 transactionid | bigint                      | not null default nextval('drilldown_id_seq'::regclass)
 userid        | bigint                      | not null default 0
 pathid        | bigint                      | not null default 0
 reqms         | bigint                      | not null default 0
 quems         | bigint                      | not null default 0
 clicktime     | timestamp without time zone | default now()
Indexes:
    "drilldown_pkey" PRIMARY KEY, btree (transactionid)
    "drilldown_idx1" btree (clicktime)
Foreign-key constraints:
    "drilldown_userid_fkey" FOREIGN KEY (userid) REFERENCES users(id)
Referenced by:
    TABLE "querystats" CONSTRAINT "querystats_transactionid_fkey" FOREIGN KEY (transactionid) REFERENCES drilldown(transactionid)

database=# \d querystats
                            Table "public.querystats"
    Column     |  Type  |                        Modifiers                        
---------------+--------+---------------------------------------------------------
 id            | bigint | not null default nextval('querystats_id_seq'::regclass)
 transactionid | bigint | not null default 0
 querynameid   | bigint | not null default 0
 queryms       | bigint | not null default 0
Indexes:
    "querystats_pkey" PRIMARY KEY, btree (id)
    "querystats_idx1" btree (transactionid)
    "querystats_idx2" btree (querynameid)
Foreign-key constraints:
    "querystats_querynameid_fkey" FOREIGN KEY (querynameid) REFERENCES queryname(id)
    "querystats_transactionid_fkey" FOREIGN KEY (transactionid) REFERENCES drilldown(transactionid)

リクエストされた 2 つのテーブルとバージョンは次のとおりです。

PostgreSQL 9.1.7 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, 64-bit

したがって、このクエリが行っているのは、クエリの種類 (querynameid) ごとに queryms のすべての行の値から平均を取得することです。

            name            |         current_setting          |        source        
----------------------------+----------------------------------+----------------------
 application_name           | psql                             | client
 client_encoding            | UTF8                             | client
 DateStyle                  | ISO, MDY                         | configuration file
 default_text_search_config | pg_catalog.english               | configuration file
 enable_seqscan             | off                              | session
 external_pid_file          | /var/run/postgresql/9.1-main.pid | configuration file
 lc_messages                | en_US.UTF-8                      | configuration file
 lc_monetary                | en_US.UTF-8                      | configuration file
 lc_numeric                 | en_US.UTF-8                      | configuration file
 lc_time                    | en_US.UTF-8                      | configuration file
 log_line_prefix            | %t                               | configuration file
 log_timezone               | localtime                        | environment variable
 max_connections            | 100                              | configuration file
 max_stack_depth            | 2MB                              | environment variable
 port                       | 5432                             | configuration file
 shared_buffers             | 24MB                             | configuration file
 ssl                        | on                               | configuration file
 TimeZone                   | localtime                        | environment variable
 unix_socket_directory      | /var/run/postgresql              | configuration file
(19 rows)

enable_seqscan=off が表示されました。設定には何も触れていません。これは完全にデフォルトのインストールです。

アップデート

以下のコメントからいくつかの変更を加えました。これが結果です。

explain analyse SELECT (SELECT avg(queryms) AS total FROM querystats WHERE querynameid=3) as total FROM querystats qs JOIN drilldown d ON (qs.transactionid=d.transactionid) WHERE qs.querynameid=3 limit 1;
                                                                       QUERY PLAN                                                                        
---------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=196775.99..196776.37 rows=1 width=0) (actual time=2320.876..2320.876 rows=1 loops=1)
   InitPlan 1 (returns $0)
     ->  Aggregate  (cost=196775.94..196775.99 rows=1 width=8) (actual time=2320.815..2320.815 rows=1 loops=1)
           ->  Bitmap Heap Scan on querystats  (cost=24354.25..189291.69 rows=2993698 width=8) (actual time=226.516..1144.690 rows=2999798 loops=1)
                 Recheck Cond: (querynameid = 3)
                 ->  Bitmap Index Scan on querystats_idx  (cost=0.00..23605.83 rows=2993698 width=0) (actual time=225.119..225.119 rows=2999798 loops=1)
                       Index Cond: (querynameid = 3)
   ->  Nested Loop  (cost=0.00..1127817.12 rows=2993698 width=0) (actual time=2320.876..2320.876 rows=1 loops=1)
         ->  Seq Scan on drilldown d  (cost=0.00..76745.10 rows=1498798 width=8) (actual time=0.009..0.009 rows=1 loops=1)
         ->  Index Scan using querystats_idx on querystats qs  (cost=0.00..0.60 rows=2 width=8) (actual time=0.045..0.045 rows=1 loops=1)
               Index Cond: ((querynameid = 3) AND (transactionid = d.transactionid))
 Total runtime: 2320.940 ms
(12 rows)
4

5 に答える 5

10

enable_seqscan = offインデックス スキャンを使用してハッシュ テーブルにデータを入力しているため、を設定したかのように動作しています。診断ステップ以外では、プランナーのオプションをオフに設定しないでください。プランを表示している場合は、使用したオプションを表示してください。これを実行して、多くの有用な情報を表示できます。

SELECT version();
SELECT name, current_setting(name), source
  FROM pg_settings
  WHERE source NOT IN ('default', 'override');

また、ランタイム環境、特にマシンの RAM の量、ストレージ システムの外観、データベースのサイズ (または、データベース内の頻繁に参照されるデータのアクティブなデータ セット)について教えていただけると助かります。 )。

大まかな内訳として、5.2 秒は次のように分類されます。

  1. querystats選択基準に一致する4,117,717 行を見つけるのに 1.3 秒かかります。
  2. drilldownそれらをレコードとランダムに照合するのに 2.3 秒。
  3. 4,117,717 行を渡し、平均を計算するのに 1.6 秒かかります。

そのため、最速の計画を使用する能力を失ったように見えても、各行を見つけて別の行に結合し、平均を計算するのに 1.26 マイクロ秒 (100 万分の 1 秒) しかかかりません。これは絶対的には悪くありませんが、ほぼ確実にわずかに速い計画を立てることができます。

まず、x が 3 未満の 9.2.x を使用している場合は、すぐに 9.2.3 にアップグレードしてください。このクエリに影響を与える可能性がある最近のリリースで修正された、いくつかのタイプのプランでパフォーマンスの低下がありました。一般に、マイナー リリース(バージョン番号が 2 番目のドットを超えて変更されている場合) では最新の状態を維持するようにしてください。

その接続のみに計画要素を設定し、クエリ (またはその接続) を実行することで、1 つのセッションでさまざまな計画をテストできますEXPLAIN。次のようなことを試してください:

SET seq_page_cost = 0.1;
SET random_page_cost = 0.1;
SET cpu_tuple_cost = 0.05;
SET effective_cache_size = '3GB'; -- actually use shared_buffers plus OS cache

すべてのenable_設定がであることを確認しますon

于 2013-02-10T15:58:33.560 に答える
3

あなたはあなたの質問で主張します:

enable_seqscan=off が表示されました。設定には何も触れていません。これは完全にデフォルトのインストールです。

対照的に、からの出力は次のことをpg_settings示しています。

enable_seqscan | オフ | セッション

enable_seqscan = off つまり、 session で設定します。ここに何かが足していません。

走る

SET enable_seqscan = on;

また

RESET enable_seqscan;

主張する:

SHOW enable_seqscan;

また、何百万ものレコードを持つデータベースには設定shared_buffers低すぎます。24MBすぐに使えるUbuntuの保守的な設定のようです。本格的に使用するには、構成ファイルを編集する必要があります。マニュアルを引用します:

1GB 以上の RAM を備えた専用データベース サーバーを使用している場合、shared_buffers の適切な開始値は、システムのメモリの 25% です。

したがって、postgresql.confファイルを編集して値を増やしてリロードします。
次に、クエリをもう一度試して、どのようenable_seqscanにオフになったかを調べてください。

于 2013-02-12T12:26:02.120 に答える
1

querystats テーブルは、ファットジャンクション テーブルのように見えます。その場合: 代理キーを省略し、自然 (複合) キー (両方のコンポーネントは既に NULL 可能ではありません) を使用し、複合インデックスを追加します。(個別のインデックスは役に立たないので、とにかく FK 制約がそれらを自動的に生成します)

-- CREATE SEQUENCE querystats_id_seq;

CREATE TABLE querystats (
    -- id bigint NOT NULL DEFAULT nextval('querystats_id_seq'),
    transactionid bigint NOT NULL default 0 REFERENCES drilldown(transactionid),
    querynameid bigint NOT NULL default 0 REFERENCES queryname(id),
    queryms bigint NOT NULL default 0,
    PRIMARY KEY(transactionid,querynameid )
);

-- ALTER SEQUENCE querystats_id_seq OWNED BY querystats.id;

--CREATE INDEX querystats_idx1 ON querystats (transactionid);
-- CREATE INDEX querystats_idx2 ON querystats (querynameid);
CREATE UNIQUE INDEX querystats_alt ON querystats (querynameid, transactionid);
于 2013-02-10T15:42:48.860 に答える
1

このクエリでは

select avg(qs.queryms) 
from querystats qs 
join drilldown d 
  on (qs.transactionid=d.transactionid) 
where querynameid=1;

テーブル「ドリルダウン」の列を使用していません。外部キー制約により、「querystats」のすべての「transactionid」に対して「drilldown」に行が存在することが保証されるため、結合は何も役に立たないと思います。私が何かを見逃していない限り、あなたのクエリは次のようになります

select avg(qs.queryms) 
from querystats qs 
where querynameid=1;

まったく参加しません。「querynameid」にインデックスがある限り、適切なパフォーマンスが得られるはずです。

于 2013-02-10T01:45:59.427 に答える
1

参加しない場合は、avg(qs.queryms)1 回実行します。

avg(qs.queryms)結合を行うと、結合によって生成された行と同じ回数実行されます。

単一の querynameid に常に関心がある場合は、副選択を入れてみてくださいavg(qs.queryms)

SELECT 
    (SELECT avg(queryms) FROM querystats WHERE querynameid=1) 
FROM querystats qs 
JOIN drilldown d ON (qs.transactionid=d.transactionid) 
WHERE qs.querynameid=1;
于 2013-02-10T04:48:47.537 に答える