総件数を同時に取得する

画面に表示すればいい件数は100件だが総件数も同時に表示なければいけない場合、COUNTを別途投げていてはパフォーマンスに悪影響が出る。データセットを取得するSQLの中で同時に総件数も取得するにはCOUNT(1) OVER()を利用する。

SELECT
    COUNT(1) OVER()
    , table_a.*
FROM table_a
LIMIT 100 OFFSET 0

ページング可能な最大件数を同時に取得する

もし総件数を表示するのでなく、ページング可能な最大件数を表示すればいいという要件の場合、さらに効率のいいSQLが書ける。

例えば、ある条件に合致するデータが50000件あり、ユーザが検索できるのはそのうち10000件とする。一画面に表示するのは100件で、LIMITとOFFSETを使ってページングを行う。

WITH core AS (
  SELECT * FROM main
  WHERE /*conditions*/
  ORDER BY /*order*/
  LIMIT 10000
)

SELECT
  COUNT(1) OVER()
  , core.*
FROM core
LEFT OUTER JOIN マスタ系テーブル ON ...
LIMIT 100 OFFSET 0

WHERE句での検査が最大10000件を満たすと止まってくれる。

WITH句のSQLでは取得件数に影響を及ぼさない結合等は行わず、最後のSQLで必要な結合を行う必要がある。
最後のSQLは100件に絞っているため、マスタ等を結合するとき、10000件分結合するのではなく100件分だけ結合すればよくなる。

ちなみに最後のCOUNT(1) OVER()(SELECT COUNT(1) FROM core)としても10000件に絞っているのでパフォーマンス上ほとんど影響は出ない。