1

私は2つのテーブルを持っています:

packages と package_to_tag の両方が MyISAM を実行しています

テーブルは次のように構成されています。

パッケージ

+----------------+------------------+----------------+
|   aid(primary) |     source       |   date(index)  |
+----------------+------------------+----------------+
|   1            |    CA            |   2013-04-05   |
+----------------+------------------+----------------+
|   2            |    FL            |   2013-05-05   |
+----------------+------------------+----------------+
|   3            |    UT            |   2012-06-13   |
+----------------+------------------+----------------+
|   4            |    VT            |   2011-04-29   |
+----------------+------------------+----------------+
|   5            |    CT            |   2013-04-10   |
+----------------+------------------+----------------+

package_to_tag package-tag の一意のインデックスであり、package_aid とタグの両方にインデックスがあります

+---------------+------------------+
|  package_aid  |     tag          |
+---------------+------------------+
|   2           |    sports        |
+---------------+------------------+
|   2           |    nba           |
+---------------+------------------+
|   1           |    food          |
+---------------+------------------+
|   1           |    burrito       |
+---------------+------------------+
|   4           |    hockey        |
+---------------+------------------+
|   4           |    sports        |
+---------------+------------------+
|   3           |    news          |
+---------------+------------------+
|   5           |    sports        |
+---------------+------------------+
|   5           |    nba           |
+---------------+------------------+

タグとしてスポーツとnbaの両方を持っているパッケージを見つけるための私の基本的なクエリは次のとおりです。

SELECT package_aid FROM package_to_tag
WHERE tag IN("sports","nba")
GROUP BY package_aid
HAVING COUNT(*) = 2

結果に日付の並べ替えを追加しようとするまで、これはうまく機能します。(私のパッケージ レコード セットは 400k の範囲のどこかにあることに注意してください)

一致するタグに基づいてソースを取得するための私のクエリは次のとおりです。

SELECT package_aid, source 
FROM package_to_tag
RIGHT JOIN packages ON packages.aid = package_to_tag.package_aid
AND tag IN("sports","nba")
GROUP BY package_aid
HAVING COUNT(*) = 2
ORDER BY date DESC
LIMIT 500

これは、400k レコードの場合、最大 5 秒かかります。dateソートを削除しない限り。その後、1 秒もかかりません。したがって、私は常に IN ステートメントでかなりの成功を収めていたので、最初の結果セットを次のように絞り込んでみました。

SELECT aid,source FROM packages
WHERE aid IN(
  SELECT package_aid FROM package_to_tag
  WHERE tag IN("sports","nba")
  GROUP BY package_aid
  HAVING COUNT(*) = 2
)
ORDER BY date DESC
LIMIT 500

レコード セット全体ではなく、約 8 ~ 10,000 レコードにのみ並べ替えを適用すると考えました。

しかし、これだけでデータベースの使用率が 100% に固定され、再起動を余儀なくされます.... 余分なタグを使用して内側の選択を合計 80 レコード以下に絞り込んだとしても。

このクエリだけを実行してみました:

SELECT package_aid FROM package_to_tag
WHERE tag IN("sports","nba")
GROUP BY package_aid
HAVING COUNT(*) = 2

これにより、1 秒以内に 8 ~ 10,000 のレコードが返されます。

私は何が欠けていますか?

4

1 に答える 1

3

MySQL の以前のバージョンではin、サブクエリの最適化に問題がありました。exists簡単な解決策は、それを句として書き直すことです。

SELECT aid,source FROM packages
WHERE exists (
  SELECT package_aid
  FROM package_to_tag
  WHERE tag IN("sports","nba") and package_aid = packages.aid
  GROUP BY package_aid
  HAVING COUNT(*) = 2
)
ORDER BY date DESC
LIMIT 500

インデックスをオンにpackage_to_tag(pages.aid, tag)すると、パフォーマンス面で大きな助けになるはずです。

于 2013-06-16T20:34:21.793 に答える