1

可能な限り最適化する必要がある MySQL クエリがあります (可能であれば、読み込み時間を 5 秒未満にする必要があります)。

クエリは次のとおりです。

SELECT domain_id, COUNT(keyword_id) as total_count
FROM tableName
WHERE keyword_id IN (SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X)
GROUP BY domain_id
ORDER BY total_count DESC
LIMIT ...
  • X は入力から得られる整数です
  • domain_id と keyword_id がインデックス化されています
  • データベースはローカルホスト上にあるため、ネットワーク速度は最大にする必要があります

WHERE 句からのサブクエリは、最大 1,000 万件の結果を取得できます。また、MySQL の場合、COUNT と ORDER BY このカウントを計算するのは非常に難しいようです。

このクエリを SOLR と混合しようとしましたが、結果がありません。一度に大量の行を取得すると、MySQL と SOLR の両方に苦労します

別のテクノロジーを使用する必要があるか、この MySQL クエリを改善する必要があるかに関係なく、同じ結果が得られるソリューションを探しています。

ありがとう!


クエリ ロジックは次のとおりです。

ドメインがあり、そのドメインで使用されているすべてのキーワードを検索しています (これがサブクエリです)。次に、最初のクエリで見つかったキーワードの少なくとも 1 つを使用するすべてのドメインをドメインごとにグループ化し、各ドメインで使用されているキーワードの数を使用して、使用されているキーワードの数で DESC 順に並べて表示する必要があります。

これが理にかなっていることを願っています

4

3 に答える 3

1

サブクエリの代わりに JOIN を試すことができます:

SELECT tableName.domain_id, COUNT(tableName.keyword_id) AS total_count
FROM tableName
INNER JOIN tableName AS rejoin
ON rejoin.keyword_id = tableName.keyword_id
WHERE rejoin.domain_id = X
GROUP BY tableName.domain_id
ORDER BY tableName.total_count DESC
LIMIT ...
于 2013-03-26T09:36:44.547 に答える
0

100%確実ではありませんが、試してみてください

SELECT t1.domain_id, COUNT(t1.keyword_id) as total_count
FROM tableName AS t1 LEFT JOIN
(SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X) AS t2
ON t1.keyword_id = t2.keyword_id
WHERE t2.keyword_id IS NTO NULL
GROUP BY t1.domain_id
ORDER BY total_count DESC
LIMIT ...

WHERE IN目標は、句をに置き換えることでINNER JOINあり、それによりはるかに高速になります。WHERE IN句は常に Mysql サーバーを苦労させますが、大量のデータでそれを行うとさらに顕著になります。クエリを読みやすく/理解しやすくする場合、データセットが小さい場合、または別の方法では不可能な場合にのみ使用WHERE INしてください (ただし、おそらく別の方法でそれを行うことができます :) )

于 2013-03-26T09:38:33.530 に答える
0

MySQL に関してできることは、カバリング インデックスを使用してクエリのディスク IO を最小限に抑え、クエリがそれらの恩恵を受けるようにもう少し効率的に書き直すことだけです。

keyword_idはテーブルの別のコピーで一致するため、 になりCOUNT(keyword_id)ますCOUNT(*)

使用するサブクエリの種類は、MySQL にとって最悪のケースであることが知られています (各行に対してサブクエリを実行します) JOIN

ご存じのとおり、クエリは次のようになります。

SELECT domain_id, COUNT(*) as total_count
FROM tableName
WHERE keyword_id IN (X,Y,Z)
GROUP BY domain_id
ORDER BY total_count DESC

複合インデックスをカバーすると最高のパフォーマンスが得(keyword_id, domain_id [,...])られるため、必須です。反対側から、クエリは次のようになります。

SELECT DISTINCT keyword_id FROM tableName WHERE domain_id = X

は、カバーする複合インデックスで最高のパフォーマンスを発揮します(domain_id, keyword_id [,...])。したがって、両方が必要です。

うまくいけば、私にはわかりませんが、後者のインデックスがある場合、MySQL はkeyword_id、サブクエリでそれらすべてを選択する必要がないことを理解できますが、インデックスにエントリがあるかどうかを確認するだけで済みます。 DISTINCT を使用しない方が適切に表現されます。

したがって、これら 2 つのインデックスを追加して、クエリを次のように書き直します。

SELECT domain_id, COUNT(*) as total_count
FROM tableName
WHERE keyword_id IN (SELECT keyword_id FROM tableName WHERE domain_id = X)
GROUP BY domain_id
ORDER BY total_count DESC

もう 1 つのオプションは、クエリを次のように書き直すことです。

SELECT domain_id, COUNT(*) as total_count
FROM (
  SELECT DISTINCT keyword_id
  FROM tableName
  WHERE domain_id = X
) as kw
JOIN tableName USING (keyword_id)
GROUP BY domain_id
ORDER BY total_count DESC

ここでも、これら 2 つの複合インデックスが必要です。

どちらのクエリがより速いかは、 の統計に依存しますtableName

于 2013-03-26T18:20:48.420 に答える