2015-09-09 3 views
5

Unten Abfrage dauert ungefähr 15 Sekunden, um Daten zurückzugeben, trotz eines Index und der id als Primärschlüssel.Reihenfolge nach Abfrage in Zeitstempelspalte ist sehr langsam

select id from my_table order by insert_date offset 0 limit 1 

Die Analyse erklären ist, wie unten

"Limit (cost=1766417.72..1766417.72 rows=1 width=12) (actual time=32479.440..32479.441 rows=1 loops=1)" 
" -> Sort (cost=1766417.72..1797117.34 rows=12279848 width=12) (actual time=32479.437..32479.437 rows=1 loops=1)" 
"  Sort Key: insert_date" 
"  Sort Method: top-N heapsort Memory: 25kB" 
"  -> Seq Scan on my_table (cost=0.00..1705018.48 rows=12279848 width=12) (actual time=0.006..21338.401 rows=12108916 loops=1)" 
"Total runtime: 32479.476 ms" 

Meine Tabelle einige andere Spalten. Aber der Typ für die insert_date ist

insert_date timestamp without time zone NOT NULL DEFAULT now(), 

Ich habe einen Index auf dieser Spalte bestimmten Datum die

CREATE INDEX my_table_insert_date_indx 
    ON my_table 
    USING btree 
    (insert_date) 
TABLESPACE somexyz_idx_ts; 

Nur wenige Werte von postgresql.conf Datei ist:

shared_buffers = more than 1GB ## just for an example 
temp_buffers = more than 1GB 
work_mem = more than 1GB 
maintenance_work_mem = more than 1GB 
dynamic_shared_memory_type = posix 
default_statistics_target = 10000 
autovacuum = on 
random_page_cost = 2.0 
cpu_index_tuple_cost = 0.0005 

ich verwende Postgres 9.3 jetzt sofort.

UPDATE ::

Ich lief die unter Abfrage vor einer Weile:

select insert_date, count(*) from my_table group by insert_date 

und die oberen paar aus dem Ergebnis ist:

"2015-04-02 00:00:00";3718104 
"2015-04-03 00:00:00";6410253 
"2015-04-04 00:00:00";538247 
"2015-04-05 00:00:00";1228877 
"2015-04-06 00:00:00";131248 

Ich habe 12 um Millionen Datensätze auf dieser Tabelle. Und die obige Zählung ist fast nah an dieser Summe.

Nicht sicher, aber könnte es ein Problem sein, dass der Index für eine Spalte erstellt wurde, die Tonnen von doppelten Werten enthält? Wenn es wahr ist, haben wir dann einen Weg?

+0

Vielleicht zu einem besseren Ort zu fragen: [dba.stackexchange.com] (http://dba.stackexchange.com) –

+0

gab es eine ähnliche Frage vor kurzem auf SO, und ich denke, die Schlussfolgerung gewesen sein könnte, dass 9.4 war besser beim Ordnen durch eine indizierte Spalte, um eine Sortierung zu vermeiden. Möchte gerne nach dieser Frage suchen. –

+0

Bitte prüfen Sie dieselbe Abfrage mit 'set enable_seqscan = off;' und zeigen Sie explain analyze output an. Wie groß ist dein Index und Tisch? '\ di + my_table_insert_date_indx',' \ dt + my_table' Befehle in psql zeigen die Größen – alexius

Antwort

2

Ihre Abfrage läuft auf meinem Computer mit PostgreSQL 9.3 und 9.4 ungefähr 160000 Mal schneller. Meine Maschine ist nichts besonderes.

-- From PostgreSQL 9.4; 9.3 is similar. 
show shared_buffers; -- 128MB 
show temp_buffers; -- 8MB 
show work_mem; -- 4MB 
show maintenance_work_mem; -- 64MB 
show dynamic_shared_memory_type; -- posix 
show default_statistics_target; -- 100 
show autovacuum; -- on 
show random_page_cost; -- 4 
show cpu_index_tuple_cost; -- 0.005 

Vorbereitung

Lasst uns einen Tisch bauen. (Sie sollten dies in Ihrer Frage getan haben.)

create table my_table (
    id serial primary key, 
    insert_date timestamp not null 
); 

-- Round numbers of rows. 
insert into my_table(insert_date) 
select timestamp '2015-04-02 00:00:00' 
from generate_series(1, 3000000) n; 

insert into my_table(insert_date) 
select timestamp '2015-04-03 00:00:00' 
from generate_series(1, 6000000) n; 

insert into my_table(insert_date) 
select timestamp '2015-04-04 00:00:00' 
from generate_series(1, 500000) n; 

insert into my_table(insert_date) 
select timestamp '2015-04-05 00:00:00' 
from generate_series(1, 1200000) n; 

insert into my_table(insert_date) 
select timestamp '2015-04-06 00:00:00' 
from generate_series(1, 131000) n; 

Erstellen Sie einen Index, und aktualisieren Sie Statistiken.

create index on my_table (insert_date); 
analyze my_table; 

PostgreSQL 9,4

Nun, welche Art von Ausführungsplan bekommen wir von Ihrer ersten Abfrage?

explain analyze 
select id from my_table order by insert_date offset 0 limit 1; 
 
"Limit (cost=0.43..0.48 rows=1 width=12) (actual time=0.014..0.014 rows=1 loops=1)" 
" -> Index Scan using my_table_insert_date_idx on my_table (cost=0.43..540656.27 rows=11200977 width=12) (actual time=0.012..0.012 rows=1 loops=1)" 
"Planning time: 0.195 ms" 
"Execution time: 0.032 ms" 

PostgreSQL 9.3

explain analyze 
select id from my_table order by insert_date offset 0 limit 1; 
 
"Limit (cost=0.43..0.47 rows=1 width=12) (actual time=0.058..0.059 rows=1 loops=1)" 
" -> Index Scan using my_table_insert_date_idx on my_table (cost=0.43..339814.36 rows=10830995 width=12) (actual time=0.057..0.057 rows=1 loops=1)" 
"Total runtime: 0.098 ms" 

Ihre Anfrage

select id from my_table order by insert_date offset 0 limit 1; 

ist unbestimmt. Es gibt 3 Millionen Zeilen mit dem niedrigsten insert_date (das Datum, das gemäß der ORDER BY-Klausel zuerst angezeigt wird). Sie wählen eine dieser 3 Millionen aus. PostgreSQL garantiert nicht, dass Sie jedes Mal dieselbe ID erhalten.

Wenn es Ihnen egal ist, welche der 3 Millionen IDs zurückgegeben werden, können Sie die Abfrage anders ausdrücken. Aber ich denke nicht, dass es 160k mal schneller ist, wenn man es anders ausdrückt.

Einige der von Ihnen eingegebenen Einstellungen können für eine bestimmte Abfrage geändert werden. So können Sie so etwas tun.

-- Don't commit or rollback . . . 
begin transaction; 
set local work_mem = '8 MB'; 

explain analyze 
select id from my_table order by insert_date offset 0 limit 1; 
-- Displays the result. 

Commit oder Rollback manuell.

commit; 

Ihre Einstellung "work_mem" wird auf den beim Start des Servers festgelegten Wert zurückgesetzt.

show work_mem; -- 4MB