4

このクエリの実行時間は 2 秒を超えています (10,000 行の場合)。このクエリを最適化することは可能ですか?

SELECT id, MIN(ABS(timestamp_a - timestamp_b))
FROM a 
  INNER JOIN b ON ( timestamp_a  between (timestamp_b - 5 * 60) 
              AND (timestmap_b + 5 * 60) )
GROUP BY id

サンプル結果 (id、timestamp_a、timestamp_b、diff):

1   1349878538  1349878539  1
2   1349878679  1349878539  2
3   1349878724  1349878539  1
5   1349878836  1349878539  1
6   1349878890  1349878641  1

表 a

CREATE TABLE `a` (
`id`  int(11) NOT NULL AUTO_INCREMENT ,
`timestamp_a`  bigint(20) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
INDEX `a` (`timestamp_a`) USING BTREE 
)

表 b

CREATE TABLE `b` (
`id`  int(11) NOT NULL AUTO_INCREMENT ,
`timestamp_b`  bigint(20) NULL DEFAULT NULL ,
PRIMARY KEY (`id`),
INDEX `b` (`timestamp_b`) USING BTREE 
)

両方のテーブルは関連していません - テーブル「b」のタイムスタンプの間にあるテーブル「a」のレコードを検索します。

編集:シンプルなソリューション(非常に高速に実行):

SELECT id, MIN(ABS(timestamp_a - timestamp_b))
FROM (SELECT id, timestamp, (timestamp - 5 * 60) timestamp_a, (timestamp + 5 * 60) timestamp_b) a
INNER JOIN b ON ( timestamp between timestamp_a AND timestamp_b )
GROUP BY id
4

1 に答える 1

0

変更されたタイムスタンプ列に関するMichaelの規則に従って、このクエリは、上記の「より高速な」クエリのパフォーマンスで、元のクエリの意図された結果を生成します。

SELECT a.id, MIN(ABS(a.timestamp_a - tmp_b.timestamp_b))
FROM (SELECT id, timestamp_b, (timestamp_b - 5 * 60) timestamp_b_minus, (timestamp_b + 5 * 60) timestamp_b_plus) tmp_b
INNER JOIN a ON ( a.timestamp_a between tmp_b.timestamp_b_minus AND tmp_b.timestamp_b_plus )
GROUP BY a.id

元のクエリがパフォーマンスの制約を経験している理由は、ON句で使用されている式のために、RDBMSがbすべての行に対して全表スキャンを実行することを余儀なくされているためです。a

「より高速な」クエリではb、「一時的な」テーブルを生成するために全表スキャンが必要tmp_bですが、インデックスを使用して、基準に基づいてa.timestamp_a適切な値を抽出できます: tmp_b.timestamp_b_minus AND tmp_b.timestamp_b_plusa

于 2013-01-04T16:24:40.257 に答える