0

実行に約 30 分かかるクエリを最適化しようとしています。私がやろうとしているのは、パーティションのプルーニングを利用して、検索される行を最小限に抑えることです。テーブルが分割される変数の範囲は、別のテーブルの変数です。mysql がすべてのパーティションを検索しているようです。

ここにテーブルがあります(無関係な部分は切り取られています):(ちなみに、int(x)がintのサイズを変更していないことに気づきました。私は、より良いことを知る前にそのテーブルを設計しました。修正しました)

expectedEvent | CREATE TABLE `expectedevent` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`eventId` int(5) NOT NULL,
`unitGroup_id` int(6) NOT NULL,
`minOccur` int(9) NOT NULL,
`periodInDays` int(4) NOT NULL,
PRIMARY KEY (`id`),
KEY `eventId` (`eventId`),
KEY `unitGroup_id` (`unitGroup_id`),
CONSTRAINT `expectedevent_ibfk_1` FOREIGN KEY (`unitGroup_id`) REFERENCES `unitgroup` (`id`)

event_message | CREATE TABLE `event_message` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`unitId` varchar(15) NOT NULL,
`eventId` smallint(6) NOT NULL,
`eventName` varchar(50) NOT NULL,
`gpsDateTime` datetime NOT NULL,
`weekInfo` tinyint(4) NOT NULL,
`odometer` int(11) NOT NULL,
...
KEY `id` (`id`),
KEY `unitId` (`unitId`,`eventId`),
KEY `eventId` (`eventId`)
...
!50100 PARTITION BY RANGE (weekInfo)
ARTITION p0 VALUES LESS THAN (1) ENGINE = InnoDB,
ARTITION p1 VALUES LESS THAN (2) ENGINE = InnoDB,

unitGroup | CREATE TABLE `unitgroup` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(60) DEFAULT NULL,

unitGroup_devices | CREATE TABLE `unitg
`id` int(11) NOT NULL AUTO_INCREMENT,
`unitGroup_id` int(11) NOT NULL,
`scopeDevice_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `unitGroup_id` (`unitGroup_id`),
KEY `scopeDevice_id` (`scopeDevice_id`)
...

このクエリには約 30 分かかります (選択、説明なし):

explain partitions
select ee.eventId, scopeDevice_id as scopeDevId, sd.unitId as unitId, count(em.id) as evtCount, minOccur, periodInDays
from expectedEvent ee left join unitGroup ug on ee.unitGroup_id=ug.id
left join unitGroup_devices ugd on ug.id=ugd.unitGroup_id
left join scopeDevice sd on ugd.scopeDevice_id=sd.id
left join event_message em on sd.unitId=em.unitId and em.eventId=ee.eventId
where gpsDateTime>=DATE_SUB(DATE(now()),INTERVAL periodInDays DAY)
and weekInfo>=WEEKOFYEAR(DATE_SUB(DATE(now()),INTERVAL periodInDays DAY))
and weekInfo <=WEEKOFYEAR(DATE(now()))
group by ee.id, ugd.scopeDevice_id;

| id | select_type | table | partitions                                                                                                                                                | type   | possible_keys               | key          | key_len | ref                                            | rows | Extra                           |
+----+-------------+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+--------+-----------------------------+--------------+---------+------------------------------------------------+------+---------------------------------+
|  1 | SIMPLE      | ee    | NULL                                                                                                                                                      | ALL    | eventId,unitGroup_id        | NULL         | NULL    | NULL                                           |    1 | Using temporary; Using filesort |
|  1 | SIMPLE      | ug    | NULL                                                                                                                                                      | eq_ref | PRIMARY                     | PRIMARY      | 4       | navsat_scope.ee.unitGroup_id                   |    1 | Using where; Using index        |
|  1 | SIMPLE      | ugd   | NULL                                                                                                                                                      | ref    | unitGroup_id,scopeDevice_id | unitGroup_id | 4       | navsat_scope.ee.unitGroup_id                   |   11 | Using where                     |
|  1 | SIMPLE      | sd    | NULL                                                                                                                                                      | eq_ref | PRIMARY,unitId              | PRIMARY      | 4       | navsat_scope.ugd.scopeDevice_id                |    1 | Using where                     |
|  1 | SIMPLE      | em    | p0,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23,p24,p25,p26,p27,p28,p29,p30,p31,p32,p33,p34,p35,p36,p37,p38,p39,p40 | ref    | unitId,eventId              | unitId       | 19      | navsat_scope.sd.unitId,navsat_scope.ee.eventId |  682 | Using where                     |
+----+-------------+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+--------+-----------------------------+--------------+---------+------------------------------------------------+------+---------------------------------+

expectedEvent にはエントリが 1 つしかないため、基本的には次のことを行うのと同じです。このクエリには約 3 分かかります (選択、説明なし):

select ee.eventId, scopeDevice_id as scopeDevId, sd.unitId as unitId, count(em.id) as evtCount, minOccur, periodInDays
from expectedEvent ee left join unitGroup ug on ee.unitGroup_id=ug.id
left join unitGroup_devices ugd on ug.id=ugd.unitGroup_id
left join scopeDevice sd on ugd.scopeDevice_id=sd.id
left join event_message em on sd.unitId=em.unitId and em.eventId=ee.eventId
where gpsDateTime>="2012-09-29"
and weekInfo>=WEEKOFYEAR("2012-09-29")
and weekInfo <=WEEKOFYEAR("2012-10-01")
group by ee.id, ugd.scopeDevice_id;

| id | select_type | table | partitions | type   | possible_keys               | key          | key_len | ref                                            | rows | Extra                           |
+----+-------------+-------+------------+--------+-----------------------------+--------------+---------+------------------------------------------------+------+---------------------------------+
|  1 | SIMPLE      | ee    | NULL       | ALL    | eventId,unitGroup_id        | NULL         | NULL    | NULL                                           |    1 | Using temporary; Using filesort |
|  1 | SIMPLE      | ug    | NULL       | eq_ref | PRIMARY                     | PRIMARY      | 4       | navsat_scope.ee.unitGroup_id                   |    1 | Using where; Using index        |
|  1 | SIMPLE      | ugd   | NULL       | ref    | unitGroup_id,scopeDevice_id | unitGroup_id | 4       | navsat_scope.ee.unitGroup_id                   |   11 | Using where                     |
|  1 | SIMPLE      | sd    | NULL       | eq_ref | PRIMARY,unitId              | PRIMARY      | 4       | navsat_scope.ugd.scopeDevice_id                |    1 | Using where                     |
|  1 | SIMPLE      | em    | p39,p40    | ref    | unitId,eventId              | unitId       | 19      | navsat_scope.sd.unitId,navsat_scope.ee.eventId |  682 | Using where                     |
+----+-------------+-------+------------+--------+-----------------------------+--------------+---------+------------------------------------------------+------+---------------------------------+

回避策として、C# アプリで expectedEvent テーブルを最初に読み取り、変数の代わりに実際の日付を使用してクエリを作成することを考えています。

ただし、これをすべて MySQL で行うことをお勧めします。クエリを最適化するにはどうすればよいですか? ExpectedEvent には最終的に多くの行が含まれます。

ありがとうございました!

4

2 に答える 2

2

MySQL は、SQL ステートメントが準備されるとき (MySQL がステートメントの実行計画を生成するとき) に「パーティション プルーニング」を行います。プランの一部として「パーティション プルーニング」を取得するには、MySQL は解析時に既知の値を必要とします。解析時に不明な値に対しては、パーティションのプルーニングは実装されません。

MySQL が SQL ステートメントを実行するとき、MySQL は最初に実行計画を準備し、次にその計画を実行します。「パーティションプルーニング」は、準備段階で決定される実行計画の詳細です。(これは、述語に定数を含むステートメントがパーティションのプルーニングを表示する理由を説明していますが、列への参照を含むステートメントにはプルーニングが表示されません。)

于 2012-10-03T20:55:36.313 に答える
1

JOINを介して値を取得するのではなく、WHERE句で実際の値を使用する必要があります。考えてみてください。MySQLがクエリの実行プランを準備するとき、テーブルの値が何のためにあるのかわかりませんgpsDateTime。したがって、必要なデータを取得するためにクエリ内の特定のパーティションのみが必要であることを知る方法はありません。

この場合、2番目の例で行ったように、クエリでフィルタで使用されている日付値を事前に取得してから、selectクエリを作成するときに実際の値を使用する方がはるかに高速です。

于 2012-10-01T20:17:57.687 に答える