2012-09-21 26 views
8

から多くのグループ化された値を取得:私はこのようなテーブル構造を持つmysqlの

CREATE TABLE `test` (
    `a` tinyint(3) unsigned DEFAULT 0, 
    `b` tinyint(3) unsigned DEFAULT 0, 
    `c` tinyint(3) unsigned DEFAULT 0, 
    `d` tinyint(3) unsigned DEFAULT 0, 
    `e` tinyint(3) unsigned DEFAULT 0 
); 

これは、0から200までの値を持ついくつかの列を持つ約30の列を持っている(a、b)は、いくつかはわずか5つの値を持っています(0,1,2,3,4)(列cd)。 aproxがあります。テーブルの120k行

Iは、各列のクエリを使用して行ごとの項目数表示する:これに伴う問題は、それが30個のクエリ(列ごとに1)を発射することであり、基本的には同じセットを乗り越え

select a, count(*) FROM test group by a; 
select b, count(*) FROM test group by b; 
select c, count(*) FROM test group by c; 
select d, count(*) FROM test group by d; 
select e, count(*) FROM test group by e; 

を毎回データの

これを行うより良い方法はありますか?

私はGROUP BY WITH ROLLUPを試しましたが、結果として大量の結果セットが生成され、個々のクエリより処理が遅くなります。

あなたはSQLfiddle上のデータの選択を表示することができます:それはすべての良い場合http://sqlfiddle.com/#!2/a9fd8/1

+0

毎回 '一時的な使用。あなたの列にソートされたインデックスを追加できますか? – edze

+0

にインデックスを追加する必要がありますか?すべての上?また、いくつかの他のフィールドが検索されていることに注意してください(私はそれらのインデックスを持っています)。 – Nin

+2

はい、グループ化する必要のある列ごとに1つの順序付きインデックス。 'a'でグループ化すると、MySQLはテーブルを' a'などでソートし始めます。私はこれがあなたのボトルネックだと思う。 – edze

答えて

2

多分このようなものはより速く動作します。

select qq, q, count(*) from 
(
select 'a' qq, a q FROM test 
union all select 'b' qq, b q FROM test 
union all select 'c' qq, c q FROM test 
union all select 'd' qq, d q FROM test 
union all select 'e' qq, e q FROM test 
) t 
group by qq, q; 
+0

のパフォーマンスは同じ – Nin

3
select 'a' as `column`, a as data, count(*) 
FROM test 
group by 'a', a 
union 
select 'b', b, count(*) 
FROM test 
group by 'b', b 
union 
select 'c', c, count(*) 
FROM test 
group by 'c', c 
union 
select 'd', d, count(*) 
FROM test 
group by 'd', d 
union 
select 'e', e, count(*) 
FROM test 
group by 'e', e 

は知らないが、少なくとも、プランナはそれを最適化する機会を持つことになります。

+0

これはオリジナルとほぼ同じです(実際は少し遅い)。 – Nin

1

EDITは:この答えは完全にオフトラックである

次のことを試してみてください。それはちょうど1パスで、クリーンなクエリではありませんが、私はそれが原因DISTINCTに実行する方法もわからない:元

SELECT 
    COUNT(DISTINCT a) AS a, 
    COUNT(DISTINCT b) AS b, 
    COUNT(DISTINCT c) AS c, 
    COUNT(DISTINCT d) AS d, 
FROM 
    t 
; 
+0

ですが、それは私には異なるアイテムの数だけでなく、そのカウントを持つアイテムの値ではありません。 – Nin

+0

おっと。私の悪い;完全にオフトラック –

0

何も、しかし、あなたは、このいずれかを試みることができます。

SELECT t.col, t.val, t.c FROM 
(
    SELECT 'a' col, a val, count(*) c FROM test GROUP BY a 
    UNION ALL 
    SELECT 'b' col, b val, count(*) c FROM test GROUP BY b 
    UNION ALL 
    SELECT 'c' col, c val, count(*) c FROM test GROUP BY c 
    UNION ALL 
    SELECT 'd' col, d val, count(*) c FROM test GROUP BY d 
    UNION ALL 
    SELECT 'e' col, e val, count(*) c FROM test GROUP BY e 
) t 

しかし、ここでパフォーマンスが問題になる場合は、同じことを@edzeの提案 - 列のインデックス(yes all 30)を提案したいと思います。スペースは必要ですが、パフォーマンスは向上します。または、このタスクのためにビューテーブル

CREATE TABLE `test_view` (
    `col` char(1), 
    `value` tinyint(3), 
    `count` int 
); 

を作成し、それが頻繁に実行される場合は単純な選択をしてください。

0

エコロジーに応じて、集計データのテーブルを一度作成し、このテーブルが変更されるたびに最新の状態に保つ方が効率的かもしれません。集計データテーブルは、それぞれの(現在の)値に対して1つの行を持ち、さらに30の追加の列を持ちます。その後、カウントを更新する元のトリガーを入れることができます。当然、元のテーブルの書き込み操作は遅くなりますが、30個のインデックスが追加されます。

+0

5つの異なる値を持つカラムにインデックスを追加することは、MySQLがおそらくそのインデックスを無視するため、役に立たない。集計表はうまくいくと思いますが、この場合はすでにいくつかの列に基づいてこの表のサブセットを選択しているため、集計表をこの場合は実行できません。 – Nin

関連する問題