0

パフォーマンス上の理由から、セカンダリ集計コンパニオン テーブルを持つ大規模な (ほぼ 10M レコード) データ テーブルがあります。集計テーブルには、集計されていないデータが定期的に入力されます。

REPLACE INTO aggregate (channel_id, type, timestamp, value, count)
SELECT channel_id, 'day' AS type, MAX(timestamp) AS timestamp, SUM(value) AS value, COUNT(timestamp) AS count FROM data 
WHERE timestamp < UNIX_TIMESTAMP(DATE_FORMAT(NOW(), "%Y-%m-%d")) * 1000 
AND timestamp >= IFNULL((SELECT UNIX_TIMESTAMP(DATE_ADD(FROM_UNIXTIME(MAX(timestamp)/1000, "%Y-%m-%d"), 
    INTERVAL 1 day)) * 1000 FROM aggregate WHERE type = 'day'), 0) 
GROUP BY channel_id, YEAR(FROM_UNIXTIME(timestamp/1000)), DAYOFYEAR(FROM_UNIXTIME(timestamp/1000));

SELECTデータが返されていない場合でも、ステートメントの一部がかなり遅い (高速 PC で 2 秒以上)ことがわかりました。アグリゲーションは組み込みデバイスで実行する必要があるため、これは懸念事項です。計画は次のとおりです。

id  select_type table       type        key     key_len rows    Extra
1   PRIMARY     data        ALL                         9184560 Using where; Using temporary; Using filesort
2   SUBQUERY    aggregate   index       ts_uniq 22      1940    Using where; Using index

サブクエリ自体はインスタントです。句の計算により、明らかにインデックスをdata使用していません。channel_id/timestampGROUP BY

CREATE TABLE `data` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `channel_id` int(11) DEFAULT NULL,
  `timestamp` bigint(20) NOT NULL,
  `value` double NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ts_uniq` (`channel_id`,`timestamp`),
  KEY `IDX_ADF3F36372F5A1AA` (`channel_id`)
) ENGINE=MyISAM AUTO_INCREMENT=10432870 DEFAULT CHARSET=latin1;

クエリをさらに最適化できますか?

更新: 要求された情報の追加

SHOW INDEXES FROM data;

Table   Non_unique  Key_name    Seq_in_index    Column_name Collation   Cardinality Null    Index_type
data    0           PRIMARY     1               id          A           9184560             BTREE       
data    0           ts_uniq     1               channel_id  A           164         YES     BTREE       
data    0           ts_uniq     2               timestamp   A           9184560             BTREE       
data    1           IDX_ADF3..  1               channel_id  A           164         YES     BTREE       

CREATE TABLE `aggregate` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `channel_id` int(11) NOT NULL,
  `type` varchar(8) NOT NULL,
  `timestamp` bigint(20) NOT NULL,
  `value` double NOT NULL,
  `count` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ts_uniq` (`channel_id`,`type`,`timestamp`)
) ENGINE=MyISAM AUTO_INCREMENT=1941 DEFAULT CHARSET=latin1;

また、GROUP BY を channel_id、timestamp に変更すると、クエリが瞬時になることにも気付きました。残念ながら、グループ化は動的に計算されるため、データ計算を列として追加することは望ましくありません。

GROUP BYグループ化するデータさえないのに、なぜインデックスがこのような問題になるのか理解できません。走ってみた

SELECT channel_id, 'day' AS type, MAX(timestamp) AS timestamp, SUM(value) AS value, COUNT(timestamp) AS count FROM data 
WHERE timestamp < UNIX_TIMESTAMP(DATE_FORMAT(NOW(), "%Y-%m-%d")) * 1000 
AND timestamp >= IFNULL((SELECT UNIX_TIMESTAMP(DATE_ADD(FROM_UNIXTIME(MAX(timestamp)/1000, "%Y-%m-%d"), INTERVAL 1 day)) * 1000 
    FROM aggregate WHERE type = 'day'), 0) 

これは同じくらい遅いので、GROUP問題はないようですか?

更新 2

その道をさらに掘り下げると、

SELECT channel_id, 'day' AS type, timestamp, value, 1 FROM data 
WHERE timestamp >= (SELECT UNIX_TIMESTAMP(DATE_ADD(FROM_UNIXTIME(MAX(timestamp)/1000, "%Y-%m-%d"), 
    INTERVAL 1 day)) * 1000 FROM aggregate WHERE type = 'day');

それでも遅い(1.4秒)ので、まったくGROUP BY問題ありません。

アップデート 3

そして、これはまだ遅いです:

SELECT channel_id, 'day' AS type, timestamp, value, 1 FROM data WHERE timestamp >= 1380837600000;

GROUP BYしたがって、問題は、節の一部であるが、channel_id、タイムスタンプ インデックスを使用できないタイムスタンプに対する内部比較であるということです。そのインデックスを強制する方法についての質問につながるのはどれですか?

4

1 に答える 1

1

year と dayofyear 列をデータ テーブルに追加し、(channel_id, year, dayofyear) にインデックスを付けます。行を挿入するときに、2 つの新しい列にデータを入力します。

于 2013-10-14T16:15:07.283 に答える