0

更新:問題は(さまざまな人が指摘しているように)クエリで日時フィールドを日付フィールドに変更しているようです。

使用DATE( all_griefs_tbl.actioned_dateが遅すぎます。actioned_date を日付フィールドに変更したり、日付と時刻フィールドに分割したりせずに、より迅速な方法はありますか?

私は 2 つのテーブルを持っています。1 つはステータスと日時フィールドを持つ多数のレコードを含み、もう 1 つは 2008 年から 2015 年の日付を持つカレンダー テーブルです。

私が取得したいのは、期間内のすべての日付と、毎日「受け入れられた」レコードの数です-その数がゼロであっても-これは次のようになります:

| Date      | number_accepted |
 ----------------------------
 2012-03-01     723
 2012-03-02     723
 2012-03-03     1055
 2012-03-04     1069
 2012-03-05     0
 2012-03-06     615
 2012-03-07     0
 2012-03-08     1072
 2012-03-09     664
 2012-03-10     859
 2012-03-11     0
 2012-03-12     778
 2012-03-13     987

私は次のことを試しましたが、データの小さなサンプル (-1000 行) で十分な速度しかありません。少なくとも60万行でうまく機能するものが必要です

SELECT calendar.datefield AS Date, 
       COUNT( all_griefs_tbl.actioned_status ) AS total_griefs
FROM all_griefs_tbl
RIGHT JOIN calendar 
   ON ( DATE( all_griefs_tbl.actioned_date ) = calendar.datefield )
   AND all_griefs_tbl.actioned_status = 'accepted'
WHERE calendar.datefield < CURDATE( )
GROUP BY calendar.datefield

ありがとう

編集:要求された実行計画

 id select_type     table           type    possible_keys     key               key_len     ref     rows    Extra
 1  SIMPLE          calendar        range   PRIMARY           PRIMARY           3           NULL    1576    Using where; Using index
 1  SIMPLE          all_griefs_tbl  ref     actioned_status   actioned_status   153         const   294975  
4

2 に答える 2

1

いくつかの考え...

最初に、db クエリで値が返されない日が必要だと述べていますが、実際には、処理されている結果セットに対してこのチェックを行います。結合を行うたびに、クエリが非常に複雑になり、それらを処理するためにより多くのメモリが必要になります。この場合、カレンダー テーブルの使用をリレーショナル データベースの特定の有効な使用方法とは見なしません。

編集:明確にするために、クエリはどのように呼び出されていますか? つまり、データベースにアクセスし、クエリを実行して結果を表示する (開発中の) プログラムはありますか? もしそうなら、プレゼンテーションの前にこのプログラムで結果を処理することをお勧めします。

all_griefs_tbl.actioned_date第二に、「結合」にコミットしている場合、これは結合を行っている列であるため、実際にはインデックスが必要です。または、 で外部キーを指定することもできますcalendar.datefield

第三に、関数を使用する必要がありますDATE(all_griefs_tbl.actioned_date)か? もうデートじゃないの?(データ型は不明ですが、これとcalendar.datefieldが同じデータ型でない場合、これはデータベース設計が悪いように見えます。)

編集:あなたの言うことを踏まえてall_griefs_tbl.actioned_date、日付列all_griefs_tbl.actioned_dateとタイムスタンプ列の2つの列に分割することをお勧めしますall_griefs_tbl.actioned_time。現時点では、結合を行うためDATE()にすべての行でこの関数を実行しています。all_griefs_tblこれにより、クエリがすぐに遅くなります。これにより、日付時刻の両方の列にインデックスを追加することもできます。これにより、結合のパフォーマンスも向上します (現在のデータベース設計を考えると、インデックスactioned_dateが役に立たなかったことに驚かないでください。つまり、DATE()関数のために、現在の列EXPLAINのインデックスを使用して再実行すると、このインデックスを使用して表示されません。)actioned_dateall_griefs_tbl

第 4 に、どのタイプの情報が に格納されるかを検討する必要がある場合がありますall_griefs_tbl.actioned_status。これをブール値に置き換えることはできますか? これにより、データの保存と処理の両方がより効率的になります。(繰り返しますが、これはデータベースの設計によって異なります。)

編集:all_griefs_tbl.action_statusより小さなデータ型に変更することを検討できます-現在はvarcharであると思いますが、これを単一の(または小さな)charデータ型、または多数のブール値に簡単に変更できます。ただし、これがパフォーマンスの主なオーバーヘッドになるとは思いません。実際には、プロジェクトのニーズに応じて、より複雑なデータベース設計の決定になります。

于 2012-04-26T14:58:45.560 に答える
1

actioned_datefrom datetime を2つの別々の日付と時刻の列に分割することをお勧めします。たとえばactioned_dateactioned_time最初の結合条件をから変更できます

ON ( DATE( all_griefs_tbl.actioned_date ) = calendar.datefield )

ON ( all_griefs_tbl.actioned_date = calendar.datefield )

インデックスを追加する

ALTER TABLE all_griefs_tbl ADD INDEX g_status_date( actioned_status, actioned_date, actioned_time );

おそらく、60万行のテーブルに対してクエリを瞬時に行うでしょう。

于 2012-04-26T16:41:55.137 に答える