3

Postgresql に 1,500 万行を超えるテーブルがあります。ユーザーはこれらの行 (アイテムとしましょう) をライブラリに保存でき、ユーザーがライブラリを要求すると、システムはユーザーのライブラリをロードします。

Postgresql のクエリは次のようになります

SELECT item.id, item.name 
FROM items JOIN library ON (library.item_id = item.id) 
WHERE library.user_id = 1

、テーブルは既にインデックスが作成され、非正規化されているため、他の JOIN は必要ありません。

ユーザーがライブラリに多数のアイテム (1,000 個のアイテムなど) を持っている場合、クエリ時間は通常増加します。(たとえば、1k アイテムの場合、クエリ時間は 7 秒です) 私の目的は、大規模なデータセットのクエリ時間を短縮することです。

私はすでにSolrを全文検索に使用しており、次のようなクエリを試し?q=id:1 OR id:100 OR id:345ましたが、Solrで効率的かどうかはわかりません。

このデータセットをクエリするための代替手段を知りたいです。私のシステムのボトルネックは、ディスク速度のようです。15 GB を超えるメモリを搭載したサーバーを購入し、shared_memoryオプションを増やして Postgresql を使用するか、Mongodb や別のメモリ ベースのデータベースなどを試すか、またはクラスター システムを作成して Postgresql にデータを複製する必要がありますか?

items:
    Column    |       Type        
 --------------+-------------------
  id           | text              
  mbid         | uuid              
  name         | character varying
  length       | integer          
  track_no     | integer          
  artist       | text[]            
  artist_name  | text            
  release      | text              
  release_name | character varying
  rank         | numeric          

user_library:

    Column    |            Type             |                              Modifiers
--------------+-----------------------------+--------------------------------------------------------------
 user_id      | integer                     | not null
 recording_id | character varying(32)       |
 timestamp    | timestamp without time zone | default now()
 id           | integer                     | primary key nextval('user_library_idx_pk'::regclass)


-------------------

explain analyze 
SELECT recording.id,name,track_no,artist,artist_name,release,release_name
FROM recording JOIN user_library ON (user_library.recording_id = recording.id)
WHERE user_library.user_id = 1;

 QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Nested Loop  (cost=0.00..10745.33 rows=1036539 width=134) (actual time=0.168..57.663 rows=1000 loops=1)
   Join Filter: (recording.id = (recording_id)::text)
   ->  Seq Scan on user_library  (cost=0.00..231.51 rows=1000 width=19) (actual time=0.027..3.297 rows=1000 loops=1) (my opinion: because user_library has only 2 rows, Postgresql didn't use index to save resources.)
         Filter: (user_id = 1)
   ->  Append  (cost=0.00..10.49 rows=2 width=165) (actual time=0.045..0.047 rows=1 loops=1000)
         ->  Seq Scan on recording  (cost=0.00..0.00 rows=1 width=196) (actual time=0.001..0.001 rows=0 loops=1000)
         ->  Index Scan using de_recording3_table_pkey on de_recording recording  (cost=0.00..10.49 rows=1 width=134) (actual time=0.040..0.042 rows=1 loops=1000)
               Index Cond: (id = (user_library.recording_id)::text)
 Total runtime: 58.589 ms
(9 rows)
4

1 に答える 1

2

まず、興味深い (一般的に使用される) データのセットがすべてのインデックスと同様にメモリに快適に収まる場合、パフォーマンスが大幅に向上するため、RAM を増やすと役立ちます。ただし、1,000 レコードの場合、レコードの具体化とクライアントへの送信に時間の一部が費やされます。

その他のいくつかの最初のポイント:

  1. 実際のプロファイリングに代わるものはありません。どこで時間が費やされているのか、あなたは驚くかもしれません。PostgreSQL では、explain analyze を使用してクエリのプロファイリングを行います。
  2. カーソルと制限/オフセットを調べます。

これらが完了するまで、より良いアドバイスを思いつくことはできないと思います。

于 2012-10-10T08:27:02.507 に答える