3

これが私のクエリです:

CREATE TEMPORARY TABLE temptbl (
  pibn INT UNSIGNED NOT NULL, page SMALLINT UNSIGNED NOT NULL)
  ENGINE=MEMORY;
INSERT INTO temptbl (
  SELECT pibn,page FROM mytable
  WHERE word1=429907 AND word2=0);
ALTER TABLE temptbl ADD INDEX (pibn,page);
SELECT word1,COUNT(*) AS aaa
  FROM mytable a
  INNER JOIN temptbl b
  ON a.pibn=b.pibn AND a.page=b.page
  WHERE word2=0
  GROUP BY word1 ORDER BY aaa DESC LIMIT 10;
DROP TABLE temptbl;

問題はSELECT word1,COUNT(*) AS aaa、特にカウントです。その選択ステートメントには 16 秒かかります。

EXPLAIN 言います:

+----+-------------+-------+------+---------------------------------+-------------+---------+-------------------------------------------------------------+-------+---------------------------------+
| id | select_type | table | type | possible_keys                   | key         | key_len | ref                                                         | rows  | Extra                           |
+----+-------------+-------+------+---------------------------------+-------------+---------+-------------------------------------------------------------+-------+---------------------------------+
|  1 | SIMPLE      | b     | ALL  | pibn                            | NULL        | NULL    | NULL                                                        | 26778 | Using temporary; Using filesort |
|  1 | SIMPLE      | a     | ref  | w2pibnpage1,word21pibn,pibnpage | w2pibnpage1 | 9       | const,db.b.pibn,db.b.page                                   |     4 | Using index                     |
+----+-------------+-------+------+---------------------------------+-------------+---------+-------------------------------------------------------------+-------+---------------------------------+

使用されるインデックス (w2pibnpage1) は次のとおりです。

word2,pibn,page,word1,id

私はこれに何日も苦労しており、インデックスの列のさまざまな組み合わせを試しています(再構築に1時間かかるため面倒です-数百万行)。

私のインデックスはどうあるべきですか、またはこのクエリを一瞬で実行するにはどうすればよいですか?

4

5 に答える 5

0

temptbl が小さい場合は、最初に大きなテーブル (mytable) を制限してから、(最終的にはインデックスによって) temptbl に結合します。

現時点では、MySQL は、より大きなテーブルのインデックスを使用して結合する方がよいと考えています。

これは、直接結合することで回避できます。

  SELECT word1,COUNT(*) AS aaa
    FROM mytable a
    STRAIGHT_JOIN temptbl b
      ON a.pibn=b.pibn AND a.page=b.page
  WHERE word2=0
  GROUP BY word1 
  ORDER BY aaa DESC LIMIT 10;

これは、mytable のインデックスを where 句に使用し、temptbl のインデックスを介して mytable を temptbl に結合する必要があります。

それでも MySQL がそれを別の方法で行いたい場合は、FORCE INDEX を使用してインデックスを使用させることができます。

于 2013-04-16T11:24:12.760 に答える
0

データ ボリュームでは、スキーマを変更しない限り、何をしても高速に動作しません。

429907私があなたを正しく理解していれば、あなたは同じページにある上位の単語を探しています.

クエリを実行するたびに、これらすべての単語を何度も数え直す必要があるため、モデル化します。

高速化するには、追加の統計テーブルを作成する必要があります。

CREATE TABLE word_pairs
        (
        word1_1 INT NOT NULL,
        word1_2 INT NOT NULL,
        cnt BIGINT NOT NULL,
        PRIMARY KEY (word1_1, word1_2),
        INDEX (word1_1, cnt),
        INDEX (word1_2, cnt)
        )

大きなテーブルにレコードを挿入するたびに更新します (cnt新しく挿入された単語と同じページにあるすべての単語の を増やします)。

このような更新には時間がかかるため、単一のサーバーではおそらく遅すぎるでしょう。そのため、複数のサーバー間でそのテーブルを分割する必要もあります。

そのようなテーブルがあれば、次のように実行できます。

SELECT  *
FROM    word_pairs
WHERE   word1_1 = 429907
ORDER BY
        cnt DESC
LIMIT   10

これは瞬時です。

于 2013-04-16T11:48:56.357 に答える