0

約1,000万のエントリのデータベースがあり、各エントリにはDATEとして保存された日付が含まれています。

一意でないBTREEを使用してその列にインデックスを付けました。

個別の年ごとにエントリ数をカウントするクエリを実行しています。

SELECT DISTINCT(YEAR(awesome_date)) as year, COUNT(id) as count
FROM all_entries
WHERE awesome_date IS NOT NULL
GROUP BY YEAR(awesome_date)
ORDER BY year DESC;

クエリの実行には現時点で約90秒かかり、EXPLAIN出力はその理由を示しています。

id | select_type | table        | type  | possible_keys | key | key_len | ref | rows     | Extra
----------------------------------------------------------------------------------------------------------------------------------------
1  | SIMPLE      | all_entries  | ALL   | awesome_date  |     |         |     | 9759848  |  Using where; Using temporary; Using filesort

行をドロップする場合FORCE KEY(awesome_date)、行は最大800万にカウントダウンされますkey_len = 4が、それでもUsing where; Using temporary; Using filesortです。

また、クエリを選択DISTINCT(MONTH(awesome_date))して実行DISTINCT(DAY(awesome_date))し、関連するWHERE条件を使用して、特定の年または月に制限します。

年、月、日の情報を別々の列に保存する以外に、このクエリを高速化したり、一時テーブルやファイルソートを回避したりする方法はありますか?

4

1 に答える 1

1

日付を 3 列に分割せずに、次のことができます。

  • まず、DISTINCT を削除する必要があります。これは役に立ちません。– ypercube 1 分前編集

  • を削除するORDER BY yearと、速度が向上します (少し)。を次のように変更Group Byします: GROUP BY YEAR(awesome_date) DESC(これは MySQL ダイアレクトでのみ機能します)。

  • を に変更COUNT(id)します (が になることはないとCOUNT(*)仮定すると、これは多くの MySQL バージョンでより高速です)。idNULL

全体として、クエリは次のようになります。

SELECT YEAR(awesome_date) AS year
     , COUNT(*) AS cnt              --- not good practise to use reserved words
                                    --- for aliases
FROM all_entries
WHERE awesome_date IS NOT NULL
GROUP BY YEAR(awesome_date) DESC ;

さらに優れた (より高速な) ソリューションは次のとおりです。

  • 列を 3 つに分割する提案 (年、月、日)

  • MySQL から MariaDB (つまり MySQL フォーク) に変更しVIRTUAL PERISTENT、その年の列を使用し、その仮想列にインデックスを追加します。

  • MySQL にとどまり、yearトリガーを使用して永続的な列を自分で追加します。

于 2012-04-24T12:24:31.017 に答える