2016-05-02 10 views
2

私は結果セットにロー番号シーケンスを含むrow_numberカラムを追加したいと思います.1は最新のアイテムで、ギャップはありません。これは動作します:チャンククエリ内のグローバル行番号

SELECT id, row_number() over (ORDER BY id desc) AS row_number, title 
FROM mytable 
WHERE group_id = 10; 

今、私はメモリ上やすいように1000年各チャンクで同じデータを照会したいと思います:

ここ
SELECT id, row_number() over (ORDER BY id desc) AS row_number, title 
FROM mytable 
WHERE group_id = 10 AND id >= 0 AND id < 1000 
ORDER BY id ASC; 

ROW_NUMBERは、すべてのチャンクの1から再開しますが、私あたかもそれが最初のケースのようにグローバルクエリの一部であるかのようになります。これを達成する簡単な方法はありますか?

答えて

1

仮定:

  • idPRIMARY KEYとして定義される - UNIQUENOT NULLを意味します。そうでなければ、NULL値や重複(ネクタイ)を処理する必要があります。

  • テーブルへの同時書き込みアクセス権がありません。スナップショットを作成した後に何が起きても気にしません。

MATERIALIZED VIEW、あなたがin your answerを発揮ようには、良い選択です。

CREATE MATERIALIZED VIEW mv_temp AS 
SELECT row_number() OVER (ORDER BY id DESC) AS rn, id, title 
FROM mytable 
WHERE group_id = 10; 

しかし、インデックスと後続の問合せは、1000年

CREATE INDEX ON mv_temp (rn); 

SELECT * FROM mv_temp WHERE rn BETWEEN 1000 AND 2000;

のチャンクで

データあなたの実装が保証ギャップレスが必要になりますを取得するには、行番号rn上にある必要がありますid列 - 行番号を追加する必要はありません。

行う場合:

DROP MATERIALIZED VIEW mv_temp; 

のインデックスが自動的に(この場合、マテリアライズド・ビュー)テーブルで死にます。

詳細と関連、:

+0

私は自分の答えを受け入れるつもりでしたが、あなたはもっと注意を払って、面白い状況で書き直しました。私の使用事例では、データのバッチをエクスポートするためにこれを使用するので、インデックス/クエリがidまたはrnで実行されるかどうかは関係ありません。私はあなたの答えを受け入れるので、それは速くなる、私は他の答えは大きなテーブルには適していないと思うようになる。 – tdma

1

最初の1000行、次の1000行などのクエリを実行する必要がありますか?

通常は、1つのクエリ(既に使用しているもの)を作成し、アプリケーションで1000個のレコードを取得し、何かそれらを実行してから次の1000個を取得します。したがって、個別のクエリの必要はありません。

しかし、そのような部分的なクエリを記述するためにかなり簡単だろう:あなたはページネーションを必要とする

select * 
from 
(
    SELECT id, row_number() over (ORDER BY id desc) AS rn, title 
    FROM mytable 
    WHERE group_id = 10 
) numbered 
where rn between 1 and 1000; -- <- simply change the row number range here 
          -- e.g. where rn between 1001 and 2000 for the second chunk 
+0

お勧めとして、私は、DB側のカーソルの概念を理解するが、残念ながら、時にはそれは、それらを使用することはできません。あなたの答えはうまくいきますが、索引付けされていない最後の "xとyの間の"フィルタのために、大きなテーブルでは非常に遅いです:pgsqlは完全なサブクエリを逐次フィルタリングして最終ページ付けを行います私のテーブルの秒:( – tdma

+0

あなたはクエリを書くが、DBMSは5001から6000までの行がどれかを知り、そのチャンクに移動するためにテーブル全体をソートしなければならない。 (Madhivananの提案は 'LIMIT'と' OFFSET'を使用することは悪い考えではありませんが、同じことが起こるはずです;サブクエリでレコードを順序付けし、チャンクに移動してからrow_numbersを与えてください) –

+1

OFFSETは – tdma

1

。あなたはROW_NUMBERでWHERE句の変更、それ(にIDの開始値を変更すると、この

SELECT id, row_number() over (ORDER BY id desc)+0 AS row_number, title 
FROM mytable 
WHERE group_id = 10 AND id >= 0 AND id < 1000 
ORDER BY id ASC; 

次の時間を試してみてください)にも同様

SELECT id, row_number() over (ORDER BY id desc)+1000 AS row_number, title 
FROM mytable 
WHERE group_id = 10 AND id >= 1000 AND id < 2000 
ORDER BY id ASC; 

orベターの下に、あなたは、OFFSETおよびLIMITのアプローチを使用することができますページネーション私はそれをこのようにやってしまった最後に https://wiki.postgresql.org/images/3/35/Pagination_Done_the_PostgreSQL_Way.pdf

+0

しかし、この+1000を実行すると、各チャンク/ページには正確に1000個の結果があると仮定します。これは、ギャップや、group_id = 10を満たさない行、右? – tdma

+0

その後、私が投稿したリンクを見てください – Madhivanan

0

用::

まず私は、一時的なマテリアライズド・ビューを作成します

CREATE INDEX idx_temp ON vw_temp USING btree(id); 

は今、私は非常に迅速にすべての操作を実行し、番号の行を持つことができます:

SELECT * FROM vw_temp WHERE id BETWEEN 1000 AND 2000; 

を、クリーンアップ操作を行った後:

CREATE MATERIALIZED VIEW vw_temp AS SELECT id, row_number() over (ORDER BY id desc) AS rn, title 
FROM mytable 
WHERE group_id = 10; 
は、それから私は、インデックスを定義

DROP INDEX idx_temp; 
DROP MATERIALIZED VIEW vw_temp; 

Thorstケットナーの答えは一番きれいなようですが、それは遅すぎるために私にとっては実用的ではありませんでした。みんなに貢献してくれてありがとう。実用的なケースでは、私はこれを使ってSphinxインデクサにデータを送る。