質問

MySQLには、ファイルに関する情報を含む非常に大きなテーブル(最大1億件のレコード)があります。情報の1つは、各ファイルの変更日です。

指定した日付範囲に収まるファイルの数をカウントするクエリを作成する必要があります。そのために、これらの範囲を指定する小さなテーブルを作成し(すべて日単位)、次のようにします。

DateRanges
range_id   range_name   range_start   range_end
1          0-90         0             90
2          91-180       91            180
3          181-365      181           365
4          366-1095     366           1095
5          1096+        1096          999999999

次のようなクエリを作成しました:

SELECT r.range_name, sum(IF((DATEDIFF(CURDATE(),t.file_last_access) > r.range_start and DATEDIFF(CURDATE(),t.file_last_access) < r.range_end),1,0)) as FileCount
FROM `DateRanges` r, `HugeFileTable` t
GROUP BY r.range_name

ただし、予想どおり、このクエリの実行には永遠に時間がかかります。これは、各ファイルでDATEDIFF()計算を実行するたびに、HugeFileTableを5回実行するようにMySQLに要求しているためだと思います。

代わりにやりたいことは、HugeFileTableレコードをレコードごとに1回だけ通過し、各ファイルについて、適切なrange_nameの合計をカウントすることです。その方法がわかりません。...

誰でもこれを手助けできますか?

ありがとう。

編集:MySQLバージョン:5.0.45、テーブルはMyISAMです

EDIT2 :コメントで求められた説明を次に示します

id  select_type  table  type  possible_keys  key  key_len  ref  rows      Extra  
1   SIMPLE       r      ALL   NULL           NULL NULL     NULL 5         Using temporary; Using filesort 
1   SIMPLE       t      ALL   NULL           NULL NULL     NULL 96506321   
役に立ちましたか?

解決

最初に、HugeFileTable.file_last_accessにインデックスを作成します。

次に、次のクエリを試してください:

SELECT r.range_name, COUNT(t.file_last_access) as FileCount
FROM `DateRanges` r
 JOIN `HugeFileTable` t 
 ON (t.file_last_access BETWEEN 
   CURDATE() + INTERVAL r.range_start DAY AND 
   CURDATE() + INTERVAL r.range_end DAY)
GROUP BY r.range_name;

MySQL 5.0.75でこのクエリを試したときに得たEXPLAINプランです(簡潔にするために編集しました):

+-------+-------+------------------+----------------------------------------------+
| table | type  | key              | Extra                                        |
+-------+-------+------------------+----------------------------------------------+
| t     | index | file_last_access | Using index; Using temporary; Using filesort | 
| r     | ALL   | NULL             | Using where                                  | 
+-------+-------+------------------+----------------------------------------------+

まだ十分なパフォーマンスが得られません。 GROUP BYを使用すると、クエリに一時テーブルが発生します。それについてあなたができることはあまりありません。

ただし、少なくともこのクエリでは、元のクエリにあったデカルト積が削除されます。


更新:相関サブクエリを使用する別のクエリを次に示しますが、<=>を削除しました。

SELECT r.range_name,
  (SELECT COUNT(*) 
   FROM `HugeFileTable` t 
   WHERE t.file_last_access BETWEEN 
     CURDATE() - INTERVAL r.range_end DAY AND 
     CURDATE() - INTERVAL r.range_start DAY
  ) as FileCount
FROM `DateRanges` r;

<=>プランには、一時テーブルまたはファイルソートが表示されません(少なくとも、テストテーブルにある些細な行):

+----+--------------------+-------+-------+------------------+--------------------------+
| id | select_type        | table | type  | key              | Extra                    |
+----+--------------------+-------+-------+------------------+--------------------------+
|  1 | PRIMARY            | r     | ALL   | NULL             |                          | 
|  2 | DEPENDENT SUBQUERY | t     | index | file_last_access | Using where; Using index | 
+----+--------------------+-------+-------+------------------+--------------------------+

データセットでこのクエリを実行し、パフォーマンスが向上するかどうかを確認します。

他のヒント

さて、file_last_accessがテーブルHugeFileTableインデックスであることを確認することから始めます。

これが可能かどうかはわかりませんが、最初に日付の制限(日付 A から日付 B までのファイル)を計算してから、 <!> gt; =および<!> lt; =を使用したクエリ。少なくとも理論的には、パフォーマンスが向上します。

比較は次のようになります:

 t.file_last_access >= StartDate AND t.file_last_access <= EndDate 

CURDATE()を削除し、SQLの各行に対してこの関数を2回実行するため、クエリに日付を入れることで、少し改善できます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top