web-dev-qa-db-ja.com

大きなテーブルでpostgresqlのIDによる検索が非常に遅い

18M行のビデオテーブルがあります。 IDで特定の動画を検索すると、完了するまでに最大6秒かかります。数ミリ秒かかる場合もあれば、最大6秒かかる場合もありますが、平均して約2秒です。

アプリケーションはherokuでホストされており、Craneデータベース( https://addons.heroku.com/heroku-postgresql )と410MBのRAMを使用しています。

これをスピードアップする方法はありますか?私はビデオを1秒あたり平均50回クエリしていますが、新しいビデオは1秒あたり50回の速度で挿入/更新されます。

explain analyze SELECT * FROM videos WHERE id = 17841464 LIMIT 1;
                                                            QUERY PLAN                                                            
----------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.00..6.43 rows=1 width=119) (actual time=2337.892..2337.894 rows=1 loops=1)
   ->  Index Scan using videos_pkey on videos  (cost=0.00..6.43 rows=1 width=119) (actual time=2337.888..2337.888 rows=1 loops=1)
         Index Cond: (id = 17841464)
 Total runtime: 2337.943 ms

テーブルは次のようになります。

 \d+ videos;
                                                           Table "public.videos"
     Column     |            Type             |                      Modifiers                      | Storage  | Stats target | Description 
----------------+-----------------------------+-----------------------------------------------------+----------+--------------+-------------
 id             | integer                     | not null default nextval('videos_id_seq'::regclass) | plain    |              | 
 uuid           | character(11)               | not null                                            | extended |              | 
 channel_id     | integer                     | not null                                            | plain    |              | 
 category_id    | integer                     |                                                     | plain    |              | 
 title          | character varying(255)      |                                                     | extended |              | 
 published_at   | timestamp without time zone |                                                     | plain    |              | 
 view_count     | bigint                      |                                                     | plain    |              | 
 like_count     | integer                     |                                                     | plain    |              | 
 dislike_count  | integer                     |                                                     | plain    |              | 
 favorite_count | integer                     |                                                     | plain    |              | 
 comment_count  | integer                     |                                                     | plain    |              | 
 disabled       | boolean                     | default false                                       | plain    |              | 
 created_at     | timestamp without time zone |                                                     | plain    |              | 
 updated_at     | timestamp without time zone |                                                     | plain    |              | 
Indexes:
    "videos_pkey" PRIMARY KEY, btree (id)
    "videos_uuid_idx" UNIQUE, btree (uuid)
    "videos_latest_by_channel_idx" btree (channel_id, published_at DESC)
    "videos_top_by_channel_idx" btree (channel_id, view_count DESC)
Has OIDs: no
3
Milovan Zogovic

正直なところ、単一値のbtreeルックアップにこれほど長い時間がかかることはありません。私はあなたの問題が単にあなたの質問にあるとは思いません。それは別の場所だと思います。

まず、書き込みが多いと言います。これはおそらく、バッファから多くのものを常に押し出し、ランダムなディスクI/Oを大量に実行していることを意味します。ボトルネックの多くが一般的なI/OとRAMの不足にあったとしても、私は驚かないでしょう。

1,800万行の場合、これらはそれほど大きく見えません。それらはすべてメモリに収まる場合があります。

とにかく、サーバーのコマンドラインにアクセスできる場合、最初に行うべきことは、CPU I/O待機対ユーザー時間対システム時間を取ることです(コードの他の場所で実行できる場合があります)。また、(ANALYSE、BUFFERS、VERBOSE)を設定してExplainを実行し、何が起こっているのかをより詳しく確認できるようにします。これらは、問題がCPUアクティビティ、低速のRAM、または大量のディスクI/Oであるかどうかを判断するのに役立ちますが、現状では、実行できることはほとんどありません。

あなたができる別のことはこれです:

VACUUM ANALYSE VERBOSE;

それがスピードアップするかどうかを確認してください。

2
Chris Travers