0

次のクエリを最適化しようとしています。

            SELECT name  
            FROM  tbl 
            WHERE user_id
                IN (".$user_ids.") 
            GROUP BY name ORDER BY SUM(counter) DESC LIMIT 10

Tbl 情報: name は VARCHAR、counter および user_id は INT です。user_id、名前は一意です。

追加しようとしましIDX(user_id, counter, name)たが、EXPLAINまだ表示されているUsing where; Using index; Using temporary; Using filesortので、何か間違っていると思います。

このようなクエリの適切なインデックスは何ですか?

4

2 に答える 2

1

以下により、パフォーマンスが向上する可能性があります。

select t.name,
      (select sum(counter) from tbl t2 where t2.name = t.name) as sumcounter
from (select distinct name
      from tbl
      where user_id IN (".$user_ids.")
     ) t
order by sumcounter desc;

次に、インデックスを何度も付けtbl(user_id, name)ますtbl(name, counter)

これが機能する場合、内部サブクエリが最初のインデックスを使用して個別の名前を取得しているためです。のネストされたサブクエリはselect、2 番目のインデックスを使用してカウントを計算します。

このようにクエリを書き直すのは好きではありません。場合によっては、必要なパフォーマンスを得る必要があるかもしれません。

于 2013-08-25T13:19:59.010 に答える
1

正しいインデックスは ですIDX(user_id, name, counter)が、インデックスからデータを取得した後、クエリで追加の計算が必要です。異なる名前の数が 10 程度の場合、できることはほとんどありません (ほとんどの時間は合計演算に費やされます)。ただし、異なる名前が多数ある場合は、SUM(counter)しきい値に関する経験的な知識を使用して、並べ替えを減らすことができます。 :

SELECT name  
FROM  tbl 
WHERE user_id IN (".$user_ids.") 
GROUP BY name
HAVING SUM(counter) > 1000 -- adjust the threshold 
ORDER BY SUM(counter) DESC LIMIT 10

UPD1. うーん、インデックスを試してみてIDX(user_id, name, counter)パフォーマンスが同じであると言う場合、数百のユーザー ID を渡さない限り (この場合、クエリの解析に時間がかかる)、実際には遅い理由がわかりません。実行のためではありません)。

UPD2. MySQL IN演算子は、いくつかの追加の魔法を行います。

expr が IN リストのいずれかの値と等しい場合は 1 を返し、そうでない場合は 0 を返します。すべての値が定数である場合は、expr の型に従って評価され、並べ替えられます。アイテムの検索は、バイナリ検索を使用して行われます。

つまり、INT 値を operator に渡すとIN (1,2,3)、それらは INTS としてソートされます。文字列として格納されている整数をシリアライズすると、IN ('1', '11', '111', '12')それらは辞書順にソートされます。並べ替えの理由は、ランダムなインデックス読み取りを排除することです。これは、演算子に多くの値を渡す場合に重要です。

于 2013-08-26T03:34:37.060 に答える