2015-09-09 12 views
5

インデックスを持つにもかかわらずデータを返すためにクエリを15秒掛けて実行し、idをプライマリキーとします。タイムスタンプ列のクエリによる処理が非常に遅い

"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" 

私のテーブルには、他のいくつかの列があり、次のようにザ・分析が説明

select id from my_table order by insert_date offset 0 limit 1 

です。

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 

私はPostgresの9.3を使用しています。しかし、insert_date用タイプは

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

は私がpostgresql.confファイルから

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

いくつかの値をある特定の日付の列に索引を持っていますたった今。

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

をし、その結果から、上位のいくつかは次のとおりです:

UPDATE ::

私はしばらく前に、以下のクエリを実行した

"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 

私は約12持っていますそのテーブルの100万レコード。上記の数は、その合計にほぼ近いです。

わかりませんが、重複した値が重複している列にインデックスが作成されているという問題がありますか?それが真実ならば、私たちは周りに何か方法がありますか?

+0

たぶん依頼するより良い場所:[dba.stackexchange.com](http://dba.stackexchange.com) –

+0

あり同様の質問がSOに最近だった、と私は結論がいることだったかもしれないと思います並べ替えを避けるために、インデックス付きの列で並べ替える方が優れていました。その質問を探すのが好きかもしれません。 –

+0

'set enable_seqscan = off;'で同じクエリをテストし、explain analyzeの出力を表示してください。あなたのインデックスとテーブルはどれくらいの大きさですか? psqlの '\ di + my_table_insert_date_indx'、' \ dt + my_table'コマンドは、サイズが – alexius

答えて

2

私のマシンでは、PostgreSQL 9.3と9.4の両方を使って約160000倍高速に実行されます。私のマシンは特別なものではありません。

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

準備

のは、テーブルを作成してみましょう。 (あなたはあなたの質問でこれをしておくべきです)

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; 

インデックスを作成し、統計を更新してください。今

create index on my_table (insert_date); 
analyze my_table; 

のPostgreSQL 9.4

、実行計画のどのような私たちはあなたの最初のクエリから入手できますか?

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" 

あなたのクエリ

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

不定です。最も低いinsert_date(ORDER BY句に従って最初に現れる日付)を持つ300万行があります。あなたは300万人のうちの1人を選ぶ。 PostgreSQLは毎回同じIDを取得する保証はありません。

返される300万のIDのうち、どれが気にしなくても、クエリを別の方法で表現できます。しかし、私はそれを違う表現は160k倍のスピードアップを与えるとは思わない。

含まれている設定の一部は、特定のクエリに対して変更することができます。だからこのようなことをすることができます。

-- 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; 

あなたのwork_mem設定は、server startで設定された値に戻ります。

show work_mem; -- 4MB 
関連する問題