3

次のデータベース スキーマがあります: https://dl.dropbox.com/u/37915176/schema.PNG

meter_relevation には 200 万件以上のレコードがあります。データは、meter_history テーブルを持つアプライアンス (デバイス) に関連付けられている複数の電気メーターから取得されます。

特定の日付範囲のデバイスのデータを取得しようとしています:

SELECT MR.* 
FROM device AS D, meter_history AS MH, meter AS M, meter_relevation AS MR
WHERE D.Id=MH.Id_Device 
   AND MH.Id_Meter=M.Id 
   AND M.Id=MR.Id_Meter 
   AND D.Id="8" 
   AND MR.Date>="2012-10-04" 
   AND MR.Date<="2012-10-04"

しかし、パフォーマンスは非常に遅く、指定された日付範囲のレコードがなくても 10 秒を取得できます。

EXPLAIN を試してみたところ、クエリが最適ではないことがはっきりとわかります。meter_relevation テーブルには、200 万を超える行の総数がリストされています: https://dl.dropbox.com/u/37915176/explain.png

助言がありますか?より良い方法はありますか?もちろん、クライアント側でいくつかの作業を行い、いくつかのクエリに分割することもできます。しかし、単一の SELECT クエリに対してより良い方法があるかどうかを知りたいです。

4

4 に答える 4

1

列にインデックスを付けることをお勧めします。

D.Id
MH.Id_Device 
MH.Id_Meter
M.Id 
MR.Id_Meter 
MR.Date
于 2012-10-04T14:48:02.827 に答える
1

それが実行しているクエリである場合、最適ではないように見えます。Dテーブルは本当に必要ありませんか?デバイスの条件が によってどのように満たされるかを見てMH.Id_device = "8"ください。

しかし、表示されていない他のフィールドがあると仮定して、次のように書き直しましょう。

SELECT MR.*
    FROM meter_relevation AS MR
    JOIN meter AS M ON ( M.Id = MR.ID_Meter )
    JOIN meter_history AS MH ON ( MH.Id_Meter = M.Id )
    JOIN device AS D ON ( D.Id=MH.Id_Device AND D.Id = "8" )
WHERE 
    MR.Date BETWEEN "2012-10-04" AND "2012-10-04";

したがって、インデックスが必要です。最初が最も重要です

CREATE INDEX mr_ndx     ON meter_relevation ( Date, Id_Meter );

ただし、上記のインデックスも削除して、代わりに使用してみてください。

CREATE INDEX mr_ndx     ON meter_relevation ( Id_Meter, Date );


CREATE INDEX m_ndx      ON meter(Id); -- This probably already exists
CREATE INDEX mh_ndx     ON meter_history( Id_Device, Id_Meter );
CREATE INDEX d_ndx      ON device (Id); -- This too probably already exists

上記は、そのように書かれている場合、同等です (ただし、MySQL はこれを認識する必要があるため、それほど遅くはないと思います)。

SELECT MR.*
    FROM meter_relevation AS MR
    JOIN meter AS M ON ( MR.ID_Meter = M.Id)
    JOIN meter_history AS MH ON (MH.Id_Device = "8" AND MH.Id_Meter = M.Id)
WHERE 
    MR.Date BETWEEN "2012-10-04" AND "2012-10-04";
于 2012-10-04T15:12:32.993 に答える
0

私の推測では、インデックスが欠落しているため、テーブルスキャンを実行しています。このビットをコメントアウトして、改善されるかどうかを確認してください。

AND MR.Date>="2012-10-04" 
AND MR.Date<="2012-10-04"

その場合は、MR.Dateのインデックスを試してください。

于 2012-10-04T14:48:07.683 に答える
0

索引付けは確かに役に立ちます。EXPLAIN を実行し、適切にインデックスを作成します。すべての外部キーと日付フィールドにインデックスを付けます。ここでは、JOIN のインデックス作成について詳しく説明します。

http://hackmysql.com/case4

一般に、最も簡単な解決策は、過度に複雑なクエリを避けることです。4 つのテーブルに参加しています。4 つのテーブルすべてのすべてのデータが本当に必要ですか? 私は通常、SELECT * クエリを避けて、必要なデータのみをフェッチしていることを確認します。

于 2012-10-04T15:04:24.283 に答える