我有一张包含11万条记录的大桌子。我想得到一条记录。
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中的其他几个查询之一。
我听说过光标,但我不知道如何使用它。
这是解释分析此查询:
"Limit (cost=4719.97..4719.97 rows=1 width=850) (actual time=6074.900..6074.901 rows=1 loops=1)" " -> Sort (cost=4719.97..4720.49 rows=208 width=850) (actual time=6074.897..6074.897 rows=1 loops=1)" " Sort Key: plc_time" " Sort Method: top-N heapsort Memory: 17kB" " -> Bitmap Heap Scan on events_log (cost=50.07..4718.93 rows=208 width=850) (actual time=248.306..6068.046 rows=6911 loops=1)" " Recheck Cond: (((machine_id = 1) AND (event_type_id = ANY ('{1,51}'::integer[]))) OR ((machine_id = 88) AND (event_type_id = ANY ('{2000,2001}'::integer[]))))" " Filter: ((plc_time BitmapOr (cost=50.07..50.07 rows=1246 width=0) (actual time=244.710..244.710 rows=0 loops=1)" " -> Bitmap Index Scan on fki_events_type_fk (cost=0.00..24.98 rows=623 width=0) (actual time=238.529..238.529 rows=832699 loops=1)" " Index Cond: ((machine_id = 1) AND (event_type_id = ANY ('{1,51}'::integer[])))" " -> Bitmap Index Scan on fki_events_type_fk (cost=0.00..24.98 rows=623 width=0) (actual time=6.177..6.177 rows=6869 loops=1)" " Index Cond: ((machine_id = 88) AND (event_type_id = ANY ('{2000,2001}'::integer[])))" "Total runtime: 6075.175 ms"
并分析表:
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. Fast translate: Scanned 3000 from 158056 pages, contains: 2369701 alive rows and 71270 dead rows. 30000 rows in example, 12488167 estimated all rows
答案 0 :(得分: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;
希望这有帮助,
Loek
答案 1 :(得分:0)
尝试在plc_time
上添加索引。它会加快查询速度。
如果没有plc_time
上的索引,由于ORDER BY plc_time
,它将始终在桌面上进行全面扫描。
UPD:尝试ANALYZE
表格。详情请http://www.postgresql.org/docs/current/static/sql-analyze.html。