読者です 読者をやめる 読者になる 読者になる

gorogoroyasu

福岡の開発会社で働いている。

limit を使うか where を使うか問題

今日学んだこと

$table->find()->limit()

は、使いドコロが肝心ということ。

limit を使うべきなのは、paginate のように、データの内容によらずDBからデータを抽出したい時。 limit を使って条件判定するべきではない。

limit を使うか where を使うか問題

例:

Table名前 : 商品タグ

id tag created
1 売れ筋 2016-07-01
2 期間限定価格 2016-07-08
3 芸能人が着用 2016-07-10
4 新着 2016-07-12

みたいなテーブルを考える

4の新着は、基本的には商品が到着したタイミングでしか使わない。
だから普段見えていて欲しい情報を表示するには、

$table->find()->order(['id' => 'asc'])->limit(3);

というコードを書けば問題ない。

ただ、この書き方が議論になった。

$table->find()->order(['id' => 'asc'])->where(['tag !=' => '新着'] );

と書いたほうがいいという宗教の人が現れたからだ。

この宗教家が!!!と思ったが、
社内で最もDBに詳しいと言われる人に聞いてみたところ、後者の書き方のほうがいいと言われた。

理由は、
1. 新しいtag が追加された時に困る から
2. DBの id は、基本意味がないものとして取り扱うから

というものであった。

理由1 は自明である。
上記のコードでは、レコードが増えた時に対応できない。
さすがに素人に毛が生えた程度の僕でもこんなミスはしない。

では、理由2は?
この理由を考えるにあたって、普段人がどのような気持ちでレコードを取り扱っているかという精神論が大切になる。

気持ちを言語化する。
それは、自然キーという考え方、サロゲートキーという考え方に起因する問題だ。

キーとは?

情報を一意に特定するために用いられる目印のこと。
自然キー、サロゲートキー、複合主キーなどがある。

自然キーとは?

自然に作られたキーのこと。
例えば、人名などがそれにあたる。
人の名前は自然発生的につけられる(と仮定する)が、
同姓同名の人がいなければ、人名で人を一意に特定することができる。
この場合、人名は自然キーの役割を果たしているといえる。
自然キー派の主張

複合主キーとは?

自然キーの派生版のような感じ。 自然キーのところに書いたが、同姓同名の人がいる場合もある。
そのような場合に、もう少し情報を足すことによって人を一意に特定できることがある。 xx さんという同姓同名のひとがいた場合でも、
○○県からお越しの xx さんといえば、人を特定できるという考え方だ。 これを 複合主キーという。

サロゲートキーとは?

フレームワーク等により割り振られる、意味を持たないキーのこと。 1から始まり、被りなく1 ずつ増加していく値が用いられる。
サロゲートキー派の主張

本題

本当に簡単な説明で済ませてしまったが、 上記が自然キーとかサロゲートキーとか言われているものだ。

上記のテーブルの例で用いられているid は、サロゲートキーだ。
すなわち、id の値はフレームワークが勝手に振った値であり、意味が無い。
つまり、 id 4新着2016-07-12 が割り当てられているということには意味が無い。
一方、 新着2016-07-12 が同一レコード内に存在するということには意味がある。

これらを端的に並べると、以下のようになる。

レコードの縦の並び順には意味が無い。  
レコード内のサロゲートキーには意味が無い。  
サロゲートキー以外の値が同一レコードに存在していることには重要な意味がある。

すなわち、

$table->find()->order(['id' => 'asc'])->limit(3);

というコードを書くと、何をしているのかがわからないのだ。
何をしているのかがわからないということは、 勝手に順番を変えられる可能性があったり(そんなことはまずないと思うが)
メンテナンシビリティが下がったり(主な問題はこれだと思う)する可能性があるということだ。

だから、一番上で書いたように、

$table->find()->order(['id' => 'asc'])->limit(3);

と書くよりも、

$table->find()->order(['id' => 'asc'])->where(['tag !=' => '新着'] );

と書くほうがずっといい ということになる。

説明が難しくて、うまく伝わったか不安だが、
少しでも同じことで悩む人が減るといいと願っています。

補足

本文中で何度か縦の並び順には意味が無い と書いたが、実は横の並び順にも意味はない。

意味があるのは、同一レコードの特定のカラムに入った情報だけだ。
ただ、長くなりそうなので続きは次回にしようと思う。

一言

ブログは1ポモドーロと決めていたが、早速ルールを破ってる。