RDB設計

今どきのページング

ページングって?

Webサイトの一覧画面って大概ページングする。

ページングとは、まさに、複数行を1画面に表示して、次のページにまた複数行を表示するようインターフェースのこと。

UIとして、画面を移動したり、画面下部に継ぎ足されたりとかいろんなパターンはあるが、そこは重要ではなく、データ構造としてどう取り出すかというのがポイント。

古くから有る例「limit」

SQLにはlimit句がある

select * from users order by id limit 20,10;

この例では、「21番め移行を10件とってきなさいよ」って命令になる。

10件ずつとってくるのは、一気に10万件とかとってきちゃうと画面のデータがいっぱいになっちゃうから。かならず上限は決める。

Webの一覧画面では、レコード数ではなく「1ページあたりの件数を決めて」「何ページ目からのスターとか」ってことで、UIをつくる。ECサイトの大半はそういう作り。

SS 2017-06-27 12.59.01.png

URLのクエリストリングにp=2とかpage=2 とかついてるから、いきなりp=10とかってやれば、いきなり後ろの方のデータを取得できる。

今風のページングは、max_id を取得

limitを使ったページングは、これはこれで、教科書どおりなんだけど、offsetって後ろの方のページになると遅いんですね。じゃぁってことで、イマドキはmax_idをつかう。max_idってのはSQLの用語ではなく、「そのページにある最大のidを覚えておいてそれより小さな件数を取得する」ということ。

Twitterなんかがまさにそうで、そのページのTweetの最大をとっておいて、それより小さなTweetIDを取得するようにしている。

RubyのActiveRecordも、バッチ処理で複数レコードを処理するときには、以下のように、処理したIDの最大を勝手に覚えてくれるので、メモリがあふれることなく、次々と処理をしてくれる。

 SELECT  `users`.* FROM `users` WHERE (`users`.`id` > 1001)  ORDER BY `users`.`id` ASC LIMIT 1000

max_idでページングするデメリット

並び順の種類が2個になっちゃう

「このid以前(以降)何件頂戴」はDBに対してはすごく速いんだけど、並び順が制御できない(idの昇順か降順)。SNSは、新着順が殆どなので、増えていくタイプのIDだと、IDの降順でだいたいこと足りる。だけどSNSのとかだと、必ずしも新着順じゃなくて、オススメ順だとかレビュー数順とかになる。

その場合は、並び順で制御するのではなく、抽出条件として「★3つ以上」とかのUIにするとかで回避。

ランダムなIDは使いづらい

そもそも、IDがオートナンバーで増えつづける方式もそれはそれで古い。オートナンバー方式だとDBが分残しにくいので、UUID的なランダムな文字列を主キーにするというスタイルも出てきている。その場合は時刻で並ばない。そんなわけで、「分散しやすいランダム文字列だけど並び順は時系列」というスタイルの主キーをつかうのがSNSでは多い。

まとめ

SNSなんかは、自由に並び替えたいというニーズよりも、「情報の鮮度」「情報の量」「レスポンスの速さ」が大事なので、絶対max_idの方がいい。