0

〜600kレコードを含む統計テーブルがあり、その上で次の(raw sql)クエリを実行してグラフの統計データを取得します。

SELECT 
(UNIX_TIMESTAMP(s.date)*1000+3600000) as time,
ROUND((s.loadtime / s.loadtimeMeasurements), 3) as loadtime 
FROM mw_statistics s 
WHERE s.type = 0 
    AND s.date >= '2013-02-01 07:52:06' 
    AND s.date <= '2013-02-01 11:52:06' 
    AND s.product_id IN (1,8,9,10,11) 
GROUP BY s.date

このクエリは、完了するまでに約1秒かかります。ほんの数百ミリ秒かかります。このクエリをどのように改善できるか考えてみてください。mysqlデータベースとinnodbエンジンでSymfony2/Doctrineを使用しています。

よろしく、ジャスパー

テーブルの構造ダンプは次のとおりです。

CREATE TABLE IF NOT EXISTS `mw_statistics` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`contentErrors` smallint(6) DEFAULT NULL,
`contentMeasurements` smallint(6) DEFAULT NULL,
`thirdpartyErrors` smallint(6) DEFAULT NULL,
`thirdpartyMeasurements` smallint(6) DEFAULT NULL,
`applicationErrors` smallint(6) DEFAULT NULL,
`applicationMeasurements` smallint(6) DEFAULT NULL,
`loadtime` double NOT NULL,
`loadtimeMeasurements` smallint(6) NOT NULL,
`unavailable` smallint(6) DEFAULT NULL,
`unavailableMeasurements` smallint(6) DEFAULT NULL,
`type` smallint(6) NOT NULL,
`step` smallint(6) DEFAULT NULL,
`date` datetime NOT NULL,
`status` smallint(6) DEFAULT NULL,
`url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`product_id` int(11) DEFAULT NULL,
`script_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `IDX_FC665E6F4584665A` (`product_id`),
KEY `IDX_FC665E6FA1C01850` (`script_id`),
KEY `date` (`date`) 
) ENGINE=InnoDB DEFAULT
  CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=2105417 ;

結合が一意であることに注意してください:(type = 0、product_id、date)または(type = 1、script_id、step、date)

4

3 に答える 3

0

日付とIDのインデックスを作成します。条件がAND p.id IN (1,8,9,10,11)後に置かれる場所でs.type = 0、以前よりもクエリが速くなることを願っています。

于 2013-02-01T09:57:48.990 に答える
0

理由を完全に確認するには、実行計画 ( で取得EXPLAIN) が必要です。

ピンチでは、インデックスが不適切または欠落しているため、1 つまたは複数のフル テーブル スキャンが関係していると思います。

次の順序でmw_statisticsINDEXが必要です。type, date, product_id

 CREATE INDEX mw_ndx ON mw_statistics ( type, date, product_id )

p.id条件をs次の場所に移動することもできます。

WHERE s.type = 0
    AND s.date >= '2013-02-01 06:12:32' AND s.date <= '2013-02-01 10:12:30'
    AND s.product_id IN (1,8,9,10,11)

...その場合、インデックスはおそらく次のようにパフォーマンスが向上します。

 CREATE INDEX mw_ndx ON mw_statistics ( type, product_id, date )

詳しく見る

という列がありますが、dateを使用して範囲を設定し、集計関数を使用せずdatetimeにグループ化します。常に1 つの dayを照会したい場合、は不必要です。列が を保持している場合、ほとんどの場合単一の項目の非常に細かい (おそらく役に立たない) グループが表示されます。GROUP BYdatetime

次に、ロードしているすべてのデータがsテーブルから取得されます。product_id統計に製品があり、後者にブランドがあることを確認するために制約を実装することで、より良いサービスが提供される場合があります。

この点で product_ids が正当であるかどうかを事前に確認することもできます。これが完了すると、クエリは次のようになります

SELECT 
    (UNIX_TIMESTAMP(date)*1000+3600000) as time,
    ROUND((loadtime / loadtimeMeasurements), 3) as loadtime
FROM mw_statistics
WHERE type = 0
    AND product_id IN (1,8,9,10,11)
    AND date BETWEEN '2013-02-01 06:12:32' AND '2013-02-01 10:12:30'
;

typeこれは、product_idおよびにインデックス付けされ、数十ミリ秒でdate実行されるはずです。

特定の試み

CREATE INDEX mw_ndx ON mw_statistics (
          type, product_id, date, loadtime, loadtimeMeasurements
     );

SELECT
    (UNIX_TIMESTAMP(date)*1000+3600000) as time,
    ROUND((loadtime / loadtimeMeasurements), 3) as loadtime
FROM mw_statistics
WHERE type = 0
  AND product_id IN (1,8,9,10,11)
  AND date BETWEEN '2013-02-01 06:12:32' AND '2013-02-01 10:12:30'
;

typeこのように、必要なレコードは、正確な選択 オンとセット選択 オンによってすばやく絞り込まれproduct_idます。date選択もうまく機能するはずです。別の状況では、パーティショニングやシャーディングを検討したいかもしれませんが、レコード数が数百万に満たない場合は、あまり意味がありません。すべてのインデックス エントリは 2 で重み付けさsmallintれますが、このわずかなオーバーヘッドを受け入れることで、実際にはメイン テーブルにまったくアクセスしなくなります

クエリの実行時間は、列のカーディナリティによって異なります。しかし、サンプルでは、​​100 万行の均等に (実際にはランダムに) データが入力されたサンプル テーブルでは、キャッシュ パフォーマンスと実際に取得された行数に応じて、8 ~ 90 ミリ秒の往復時間が得られます。

より正確なチューニングを行うには、の出力が必要ですEXPLAIN SELECT (UNIX_TIMESTAMP...

于 2013-02-01T09:59:49.730 に答える
0

本当に mw_brands に参加する必要がありますか? そこからのデータを使用していないので、現在の唯一の使用は、mw_statistics が (mw_products を介して) mw_brands に関連付けられていることを確認することです?

必要ない場合は、両方の結合を削除し、p.id in (1,8,9,10,11) を (1,8,9,10,11) の s.product_id に変更します。

于 2013-02-01T10:00:34.187 に答える