如何在大数据库中获得第一个结果(有序)

时间:2012-11-23 13:42:13

标签: sql postgresql sql-order-by limit plpgsql

我有一张包含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

2 个答案:

答案 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

相关问题