SQLでの日付条件に注意
以下のエントリーを読んでいて、過去に自分もハマッたなあと思ったのでメモ。
ヒビコレショウジン - フレームワーク開発時代のSQLチューニング基礎(2)SQLのやっちゃだめ前編 について確認してみた
※ほとんど引用のみになっちゃいました。。
SELECT empno, ename, hiredate FROM emp
WHERE TO_CHAR(hiredate, 'YYYY/MM/DD') = '2011/02/16';
よくありがちですが、これはHIREDATE列にINDEXがあっても使えません。
列値が関数などで加工されると、INDEX内の列値を使ってマッチングができないからですね。
日付での絞り込みが遅いシステムの原因としてよく見かけます。
これは常識ですね。いつも気をつけています。
でも、この書き方じゃINDEXが使えないのはわかったので、改良してみます。
SELECT empno, ename, hiredate FROM emp
WHERE hiredate = TO_DATE('2011/02/16', 'YYYY/MM/DD');
で、これを実行すると、データが1件もヒットしなかったりします。
原因は、DATE型は年月日 時分秒を持っているため、「年月日」だけの文字列を変換すると、時刻部分は00:00:00扱いになるためです。
ココ!!注意。不具合としてよくありがち。
なので、時刻部分は無視できるようにします。
SELECT empno, ename, hiredate FROM emp
WHERE hiredate >= TO_DATE('2011/02/16 00:00:00', 'YYYY/MM/DD HH:MI:SS')
AND hiredate <= TO_DATE('2011/02/16 23:59:59', 'YYYY/MM/DD HH:MI:SS');
betweenのほうがすっきりするかもしれませんが。
同様に、データ型の暗黙変化でもINDEXは使えなくなるので、文字と数値の比較などを行わないように注意が必要です。
- 条件指定する列自体を関数で加工するとINDEXが利かないよね。
- だから、条件指定する値のほうを加工しちゃえ!
- あれ、正しい条件のはずが、一件もヒットしない(時刻部分は00:00:00扱いだから)
という感じで間違えちゃうんですよね。以前、ほぼ同じ間違いをやって、同じような修正をして記憶が。。。みなさんもお気をつけください。