MySQL oddíl prořezávání na proměnné

hlasů
0

Já jsem se snaží optimalizovat dotaz, který užívá asi 30 minut běžet. To, co se snažím udělat, je využít dělicí prořezávání, aby se minimalizovalo řádky prohledány. Rozsah proměnné, kterou je tabulka rozdělena je proměnná z jiné tabulky. Zdá se, že mysql hledá všechny oddíly.

Zde jsou tabulky (přířezy na to, že jsou irrevelant): (Uvědomuji si, mimochodem, že int (x) se nemění velikost int jsem navrhl tuto tabulku než se dozví, tím lépe, a útočiště‘. t je pevná)

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`)
...

Tento dotaz trvá asi 30 min (select, bez vysvětlení):

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                     |
+----+-------------+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+--------+-----------------------------+--------------+---------+------------------------------------------------+------+---------------------------------+

K dispozici je pouze jedna položka v expectedEvent, takže je v podstatě stejné jako provedení následující. Tento dotaz trvá asi 3 minuty (select, bez vysvětlení):

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                     |
+----+-------------+-------+------------+--------+-----------------------------+--------------+---------+------------------------------------------------+------+---------------------------------+

Můj nápad pro řešení čte v mém C # aplikace tabulka expectedEvent první, pak budování dotaz s reálnými daty namísto proměnné.

Já bych však raději, jak to udělat všechno v MySQL. Jak lze optimalizovat dotaz? ExpectedEvent nakonec bude obsahovat mnoho řádků.

Děkuji!

Položena 01/10/2012 v 19:08
zdroj uživatelem
V jiných jazycích...                            


2 odpovědí

hlasů
1

Budete muset použít skutečné hodnoty v klauzuli WHERE, nedostane hodnotu přes JOIN. Přemýšlejte o tom, kdy MySQL připravuje plán spuštění pro dotaz, ale nemá představu o tom, jaké hodnoty v tabulce je pro gpsDateTime. Z tohoto důvodu nemá žádný způsob, jak vědět, že potřebuje pouze určité oddíly v dotazu získat data, které potřebuje.

Ve vás případě by bylo mnohem rychlejší získat hodnotu data používaný ve filtru s dotazem předem a pak použít skutečnou hodnotu při provedení výběrového dotazu, jako jste udělal ve svém druhém příkladu.

Odpovězeno 01/10/2012 v 19:17
zdroj uživatelem

hlasů
2

(., Když MySQL generuje plán spuštění pro výkaz) MySQL dělá „oddíl prořezávání“, když je připraven příkaz SQL Chcete-li získat „oddíl prořezávání“ jako součást plánu, MySQL potřebuje hodnoty, které jsou známé v době analýze; oddíl prořezávání není implementován na hodnoty, které jsou v analýze čas neznámé.

Když MySQL spustí příkaz SQL, MySQL nejprve připraví plán spuštění, a pak se spustí tento plán. „Partition prořezávání“ je detail plán provádění, který rozhoduje ve fázi připravit. (To vysvětluje, proč vaše prohlášení s konstantami v dělicí prořezávání predikát show, ale váš výrok, který obsahuje odkazy na sloupce nevykazuje prořezávání).

Odpovězeno 03/10/2012 v 19:55
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more