4

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

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

代わりに、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   
4

3 に答える 3

4

まず、にインデックスを作成します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;

EXPLAINMySQL 5.0.75でこのクエリを試したときに得た計画は次のとおりです(簡潔にするために編集しました)。

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

それでもうまく機能しません。を使用するGROUP BYと、クエリに一時テーブルが発生しますが、これはコストがかかる可能性があります。それについてできることはあまりありません。

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


更新: 相関サブクエリを使用する別のクエリがありますが、を削除しました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;

計画には、一時テーブルまたはファイルソートは表示されません(EXPLAIN少なくとも、テストテーブルにあるわずかな量の行では)。

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

データセットでこのクエリを試して、パフォーマンスが向上するかどうかを確認してください。

于 2009-05-02T01:56:40.620 に答える
1

まず、 が tableのインデックスfile_last_accessであることを確認します。HugeFileTable

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

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

 t.file_last_access >= StartDate AND t.file_last_access <= EndDate 
于 2009-05-01T18:17:12.830 に答える
0

CURDATE() を削除してクエリに日付を入力すると、SQL の各行に対してこの関数が 2 回実行されるため、わずかな改善が得られます。

于 2009-05-01T22:43:44.327 に答える