電子書籍の厳選無料作品が豊富!

テーブル設計について。

DBから集計して、このような表を出しているのですが、
現在、レコードが10万件ほどあり、集計のクエリが終わるまで7秒近くかかっています。

※以下、タブ区切りにしてありますので、エディタなどに貼り付けて頂くと見やすいと思います。

【表】
質問グループ質問タグ答えOK数答えNG数
Aa21
Ab20
Ba12

【DB】
テーブル:test
idanswergrouptag
1OKAa
2NGAa
3OKAa
4OKAb
5OKAb
6OKBa
7NGBa
8NGBa

【クエリ】
SELECT group, tag,
SUM(CASE WHEN answer='ok' THEN 1 ELSE 0 END) AS ok,
SUM(CASE WHEN answer='ng' THEN 1 ELSE 0 END) AS ng
FROM test
GROUP BY group, tag;

※「id」をprimaryキー、「group、tag、answer」をまとめてuniqueとしてインデックスを貼ってます

ok数とng数の集計に時間がかかってしまっているのですが、
他に良い方法があれば教えて下さい。

また、そもそものテーブル構成を以下のようにすればいいのでは?
とも思ったのですが、どうなんでしょうか?
この形に変えると、集計は一瞬で終わるはずなのですが、
ok と ngを別カラムにするという考え方がしっくりきません。
テーブル構成の考え方としてどうなのか知りたいです。
下のようにすると、okカラムとngカラムの片方にしか値は入らなくなってしまうので、
それだったら最初の構成のように、answerカラムにokかngのどちらかが入るといった方が好ましいのかなとも思い・・
それと今回はたまたまok と ngの固定2つですが、複数になるような場合もあると思うのです。

テーブル:test
idgrouptagokng
1Aa1NULL
2AaNULL1
3Aa1NULL
4Ab1NULL
5Ab1NULL
6Ba1NULL
7BaNULL1
8BaNULL1

SELECT group, tag, sum(ok), sum(ng)
FROM test
GROUP BY group, tag;


ご教示下さい。

A 回答 (6件)

>「group、tag、answer」をまとめてuniqueとしてインデックスを貼ってます



ごめんなさい、意味不明なところがあります
uniqueはただの入力制限でindexは高速化処理ですよ。
unique”として”インデックスは貼れません。
uniqueしか貼っていないなら早くはならないと思いますが・・

とりあえず
alter table test add index(`answer`,`group`,`tag`);
してみてください
    • good
    • 0
この回答へのお礼

回答遅くなり申し訳ありません。
「group、tag、answer」をuniqueとしてindex貼っていたのがよくなかったです。
この点勘違いしておりました。
再度、「group、tag、answer」に対して複合インデックスを貼り直したところ速くなりました。
ありがとうございました。

お礼日時:2011/02/17 10:12

このクエリだと、EXPLAINでtype=index、Extra=Using indexの状態であれば、それ以上高速化できないように思います。

手元のマシンで試してみましたが、26万件程度のデータで0.23秒でした。7秒もかかるということは、他に原因があるのかも知れません。(ディスクI/Oが発生しているのかも知れませんので、バッファの調整をおすすめします。)
    • good
    • 0

#4さんの言うとおり、uniqueはインデックス対象でした。

すみません
実際のところ今回の場合uniqueではないので、意味がないと言いたかったんですが
蛇足でしたね
    • good
    • 0

ちょっと集中力がない状態なのですが、取りあえず追記。




> uniqueしか貼っていないなら早くはならないと思いますが・・

ん?
表定義でuniqueで一意性制約を指定すると、その実装のためにMySQLでも内部的にインデクスが作成されますが、違う意味かな。。。create unique indexでも定義できますし。
もちろん、このユニークチェックのためのインデクスは、検索の性能を出すためにも活用できます。


提示された情報だけから見ると、母体データの全行、全列を見ることになるので、オプティマイザがどう動いているのか。グループ化のためにソートが必要だし。
他にもっとたくさん列があるとか、母体データから一部分の抽出だったらとか。

昇順、降順を混在された複合キーだと、MySQLは内部的に全部昇順にするいった制限があり、昇順、降順を混在したソートするような指定をするとインデクスを使ってくれないといったケースもありますが、詳しい提示がないのでその辺は省略します。

EXPLAINの結果を見てもらったり、もっと詳しい具体的な定義内容を提示してくれるとかあれば、また別のアドバイスができるかも知れませんが、取りあえず今回はここまで。
    • good
    • 0

ちなみに・・・



サブクエリをつかってこんな風にもできますが、効率は変わりません

SELECT `group`, tag, sum(answer='ok')*counta as ok,sum(answer='ng')*counta as ng
from (SELECT `group`, tag,answer,count(*) as counta FROM test GROUP BY `group`, tag,answer
) as sub
GROUP BY `group`, tag
    • good
    • 0

MySQLのバージョンを、MySQL 4.1、MySQL 5.0、MySQL 5.1といったレベルまで、最低限提示するようにしてください。



EXPLAINを実行して、どういう処理方法になっているか結果を見てみましたか?

http://dev.mysql.com/doc/refman/5.1/ja/explain.h …
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!