1

1100万レコードの大きなテーブルがあります。レコードを1枚手に入れたい。

SELECT * 
FROM "PRD".events_log 
WHERE plc_time < '2012-11-19 14:00' 
  AND ((event_type_id IN (1,51) 
       AND machine_id = 1 
       AND island_id = 88) 
   OR (event_type_id IN (2000,2001) 
       AND machine_id=88)) 
ORDER BY plc_time desc 
LIMIT 1

両側で plc_time を制限していないため、このクエリを注文するコストは大きくなります。これを制限することはできないので、これを高速化できますか?

私は重要なフィールドにインデックスを持っているので、それがないことは問題になりません。

このクエリは、関数 pl/pgsql の他のクエリの 1 つです。

カーソルについて聞いたことがありますが、どのように使用すればよいかわかりません。

これは、このクエリを分析する説明です:

「制限 (コスト=4719.97..4719.97 行=1 幅=850) (実際の時間=6074.900..6074.901 行=1 ループ=1)」
" -> 並べ替え (コスト = 4719.97..4720.49 行 = 208 幅 = 850) (実際の時間 = 6074.897..6074.897 行 = 1 ループ = 1)"
" ソートキー: plc_time"
「ソート方法:トップNヒープソート メモリ:17kB」
" -> events_log のビットマップ ヒープ スキャン (コスト = 50.07..4718.93 行 = 208 幅 = 850) (実際の時間 = 248.306..6068.046 行 = 6911 ループ = 1)"
" 条件を再確認: (((machine_id = 1) AND (event_type_id = ANY ('{1,51}'::integer[]))) OR ((machine_id = 88) AND (event_type_id = ANY ('{2000,2001 }'::整数[]))))"
" フィルタ: ((plc_time BitmapOr (cost=50.07..50.07 rows=1246 width=0) (actual time=244.710..244.710 rows=0 loops=1)"
" -> fki_events_type_fk のビットマップ インデックス スキャン (コスト = 0.00..24.98 行 = 623 幅 = 0) (実際の時間 = 238.529..238.529 行 = 832699 ループ = 1)"
" インデックス条件: ((machine_id = 1) AND (event_type_id = ANY ('{1,51}'::integer[])))"
" -> fki_events_type_fk のビットマップ インデックス スキャン (コスト = 0.00..24.98 行 = 623 幅 = 0) (実際の時間 = 6.177..6.177 行 = 6869 ループ = 1)"
"インデックス条件: ((machine_id = 88) AND (event_type_id = ANY ('{2000,2001}'::integer[])))"
「合計実行時間: 6075.175 ミリ秒」

そしてテーブルを分析します:

INFORMACJA: analizowanie "PRD.events_log"
INFORMACJA: "events_log": przeskanowano 30000 z 158056 stron, zawierających 2369701 żywych wierszy i 71270 martwych wierszy; 30000 wierszy w przykładzie, 12488167 szacowanych wszystkich wierszy
Zapytanie zostało wykonane w 52203 ms i nie zwróciło żadnych wyników.

高速翻訳:
158056 ページから 3000 をスキャン:
2369701 の有効な行と 71270 の無効な行。
例では 30000 行、12488167 はすべての行を見積もった
4

2 に答える 2

1

クエリを見てみると、event_type を選択するためのサブクエリを作成するとどうなるでしょうか。順序付けに最も時間がかかり、サブクエリを使用すると処理する必要があるデータが減る可能性があると想像できます。

select * from "prd".events_log where plc_time < '2012-11-19 14:00' and id in (
 select e.id from "prd".events_log e where (e.event_type_id IN (1,51) etc...
   AND machine_id=88))) ORDER BY plc_time desc LIMIT 1;

別の解決策は、別のサブクエリを使用してメモリ内のデータを最小化することです。

select * from "prd".events_log where id in (select e.id from etc..);

全体のアイデアは、必要なときにのみ行の残りを要求することです。

カーソルのあるコードは次のようになります。

create or replace function use_lock returns int as $$
declare
 cur refcursor;
 rec RECORD;
begin
 open cur for select .... ;
 loop
  fetch cur into rec;
  exit when not found;
  ..business logic working on the record.
 end loop;
 close cur;
END;
$$ LANGUAGE PLPGSQL STABLE;

お役に立てれば、

ルック

于 2012-11-27T07:55:33.420 に答える
0

にインデックスを追加してみてくださいplc_time。これにより、クエリが高速化されます。

インデックスがないplc_timeと、常にテーブルのフル スキャンが実行されますORDER BY plc_time

UPD:ANALYZEテーブルを試してください。詳細はこちらhttp://www.postgresql.org/docs/current/static/sql-analyze.html .

于 2012-11-23T13:59:21.930 に答える