2010年 3月 9日 はてなブックマーク -
タグ: #MySQL

InnoDBでCOUNT()を扱う際の注意事項あれこれ。

InnoDBを使うとき、MyISAMと比較して度々やり玉に挙げられるポイントとして「COUNT()が遅い」というものがある。確かにInnoDBにおいて行数を弾き出すのにはテーブルスキャンが必要なのだが、そもそもMyISAMのCOUNT()が速い(テーブルの行数を保持してる)のが特殊なのであって、InnoDBが遅いわけではないのである。とはいえ、高速なCOUNT()については需要が多く、この問題には多くの人取り組んでおられるようだ。しかしながら、COUNT()のチューニングについては未だ語られていない点があるように見受けられるので、今日はCOUNT()のチューニングについて解説しようと思う。

COUNT(*)、COUNT(col)、COUNT(1)の違い

基本的なことではあるが、COUNT(*)とCOUNT(col)では意味が異なるため、異なる結果が返される場合がある。COUNT(*)はフェッチした全ての行をカウントするが、COUNT(col)ではcolがNULLでない値の場合だけカウントされるという違いがある。colというように単一のカラムではなく、COUNT()の中身はもう少し複雑な式であっても良い。以下に、この違いがはっきり分かる簡単な例を示す。

漢(オトコ)のコンピュータ道: InnoDBでCOUNT()を扱う際の注意事項あれこれ。

要約してみました。

InnoDBではcount(*)が遅いのが有名であり、その解決法としてトリガを使う方法やMIN()/MAX()を使う方法が有効なときがある。
ただMyISAMがいつでも高速なわけではなく、次のような場合には、MyISAMにおいても高速に行数を取得することは出来ない。
・NULL値が含まれる可能性のあるカラムをCOUNT(col)する場合
・GROUP BY句を利用する場合
・WHERE句で行数をカウントする範囲を限定する場合

それを解決する方法として、決定的なものはないが、場合によって有効な方法がある。
・セカンダリインデックスを追加する(countは早くなるが全体的に遅くなる可能性がある)
・Covering Indexを利用する(そこまで複雑でなく、クエリの種類が多くない場合) ※こちらは以前の記事で詳細が記述されています。
・トリガを利用する(INSERTが遅くなるデメリットがある)

どちらも場合によっては使えるというものなので、使いどころを吟味しつつ使いたいですね。


2年前 | | 2010年 3月 9日 | このエントリーを含むはてなブックマーク