Django ORMが勝手にLIMIT21を付けてくる なんで??
結論:Django ORMが負荷対策のために「LIMIT 21」を自動で付けてくれるっぽい
発行されたクエリを確認中、queryset側でLimit21の指定をしていないのにしれっとLIMIT21が付いてきました。
しかもpkをWHERE句で指定しているクエリでLIMITが付いてきていたので感覚としては結構気持ち悪かった
なんでや・・・なんで・・・・どうして・・・21・・・?
SELECT
"auth_user"."id",
"auth_user"."password",
"auth_user"."last_login",
"auth_user"."is_superuser",
"auth_user"."username",
"auth_user"."first_name",
"auth_user"."last_name",
"auth_user"."email",
"auth_user"."is_staff",
"auth_user"."is_active",
"auth_user"."date_joined"
FROM
"auth_user"
WHERE
"auth_user"."id" = 1
LIMIT
21; ←😄
ちゃんと書いてあった
議論がなされているIssue/PR
get()で負荷対策いる?
get()は単一のオブジェクトを返すため、多くの場合、pkなどの一意なフィールドを指定して使うことが一般的です。その状況下において負荷対策は必要あるのか?と思っていたのですが、読み進めると成功ケースではあまり意味がないとのこと。それをわかった上でやっているよ!ってことも書いてありました。
このLIMITはget()を誤った形で使った場合にメリットがあるようです。
get()を誤った形で使った場合、例えばヒットするデータが0件だったり、複数ヒットしてしまうようなケースでは、全行に対して検索が走ってしまう可能性があります。そのため、Django側ではあらかじめデータベースに対して取得する行数を制限し、処理を効率化しているようです。
それはわかったけどなんで21?
Issueを読む限りは以下理由のようです(英語が苦手なので間違っていたらご指摘ください🙇♀️)
- 最大21行を取得することで「明らかにエラーとわかる状況」を作り出すため
- 適切なパフォーマンスを維持するための妥協点であるため(極論、10でもいいし20でもいい)
たとえば・・・
LIMIT 2 の場合
「重複がある」とは分かるが、それが軽微な問題(2行だけ)なのか、大きな問題(20行以上)なのか判断できない。
LIMIT 21 の場合
結果が21行なら「さらにデータがある可能性」が分かり、異常の規模が把握しやすくなる。
DB周りだと、重複データが登録されてしまっている?キャッシュがおかしくなっている?フィルタ条件が不適切?など様々な要因が考えられるもんなあ。
結論
- 負荷対策のために「LIMIT 21」を付けている
- 21件にしているのはキメ。異常な状況を確実に確認できるから2件にしていない
こんなところでしょうか!
おわり!
さいごに
この記事は、クロスマート・テックアドカレ11日目の記事でした!
明日の記事もおたのしみに🎄
Discussion