4

私の問題は次のとおりです。

2,300 万行(1 年間のデータ)を含むテーブル メールメッセージがあります。
このテーブルの重要なフィールドは次のとおりです

  • id (bigint)
  • msgtimeutc (bigint)
  • 件名 (小さなテキスト)
  • 本文)
  • 表示されるその他のデータ

このテーブルには全文索引があります:
CREATE FULLTEXT INDEX mailmessage_fulltext ON mailmessage (body,subject)

本文と件名のテキストを検索し、次のように msgtimeutcで日時で絞り込むリクエストを行う必要があります。

SELECT M.some_data  
FROM mailmessage M 
WHERE M.MSGTIMEUTC >= 1343651965 AND M.MSGTIMEUTC <= 1344170365 
AND ( MATCH (M.BODY,M.SUBJECT) AGAINST ('test')); 

mySQL

  • 同時に 2 つのインデックスを使用することはできません (msgtimeutc のインデックスと fulltextindex のインデックス)。したがって、クエリは msgtimeutc で完全なテーブル スキャンを実行して終了します。
  • msgtimeutc は bigint であるため、フルテキスト インデックスに含めることはできず、その上または下で実行しています。

そのため、クエリに時間がかかりすぎます (および I/O) !

このような交差を行うことを考えました (サンプル コードはテストされていません) 。

SELECT M1.some_data FROM mailmessage M1 
WHERE M1.MSGTIMEUTC >= 1343651965 AND M1.MSGTIMEUTC <= 1344170365 
INTERSECT
SELECT M2.some_data FROM mailmessage M2 
WHERE ( MATCH (M2.BODY,M2.SUBJECT) AGAINST ('test')); 

説明してください(スクロールバーで申し訳ありません):

+----+-------------+-------+----------+---------------------------------+----------------------+---------+------+------+-------------+ 
| id | select_type | table | type     | possible_keys                   | key                  | key_len | ref  | rows | Extra       | 
+----+-------------+-------+----------+---------------------------------+----------------------+---------+------+------+-------------+ 
|  1 | SIMPLE      | M     | fulltext | msgtimeutc,mailmessage_fulltext | mailmessage_fulltext | 0       |      |    1 | Using where |
+----+-------------+-------+----------+---------------------------------+----------------------+---------+------+------+-------------+ 

しかし、それはmySQLには存在しません

以下の 2 つのような他のリクエストも、フル テーブル スキャンを実行しています。

SELECT M.some_data 
FROM mailmessage M 
WHERE 
M.id in ( 
   select m2.id from mailmessage m2 use index(mailmessage_fulltext)
   where (MATCH (m2.BODY,m2.SUBJECT) AGAINST ('test')) 
) 
AND M.MSGTIMEUTC >= 1343651965 AND M.MSGTIMEUTC <= 1344170365;

また

SELECT M1.ATTACHMENTCOUNT AS ATCH_COUNT 
FROM mailmessage AS M1 
INNER JOIN mailmessage AS M2 ON M1.id = M2.id 
WHERE (M1.MSGTIMEUTC >= 1343651965 AND M1.MSGTIMEUTC <= 1344170365) 
AND (MATCH (M2.BODY,M2.SUBJECT) AGAINST ('test'))

両方のクエリ Explain Plan で、使用されているインデックスが 1 つだけ表示されます (フルテキスト)

だから私は日付でプログラム的に行をフィルタリングすることになるかもしれません...しかし、私は(ボリュームに関して)データベースソリューションを好むでしょう

何か案が ?

4

1 に答える 1

1

最新の MySQL バージョンでは、フルテキスト インデックスを別のインデックスと組み合わせる方法はありません。

http://dev.mysql.com/doc/refman/5.6/en/index-merge-optimization.html

インデックス マージは、フルテキスト インデックスには適用できません。将来の MySQL リリースでこれらをカバーするように拡張する予定です。

一時テーブルに関する問題の回避策を試すことができます。

CREATE TEMPORARY TABLE my_search 
  (FULLTEXT INDEX mailmessage_fulltext(body,subject))         
SELECT M.some_data  
FROM mailmessage M 
WHERE M.MSGTIMEUTC >= 1343651965 AND M.MSGTIMEUTC <= 1344170365

そして、それをクエリと照合します

SELECT M.some_data  
FROM my_search M 
WHERE ( MATCH (M.BODY,M.SUBJECT) AGAINST ('test'));

このソリューションでは、実際のテーブルのフルテキスト インデックスはまったく役に立たなくなることに注意してください。

于 2012-08-13T14:48:28.650 に答える