2016-07-29 3 views
0

это мой простой внутреннее соединение:MYSQL INNER JOIN медленно с индексом

SELECT 
     SUM(ASSNZ.assenzeDidattiche) AS TotaleAssenze, 
     SUM(ASSNZ.ore) AS totale_parziale, 
     FLOOR(((SUM(ASSNZ.assenzeDidattiche)/SUM(ASSNZ.ore)) * 100)) AS andamento, 
     MAX(ASSNZ.dataLezione) AS ultima_lezione, 
     ASSNZ.idServizio, 
     ASSNZ.idUtente 
    FROM 
     ciac_corsi_assenze AS ASSNZ 
    INNER JOIN 
     ciac_serviziAcquistati_ITA AS ACQ 
       ON ACQ.idContatto = ASSNZ.idUtente 
       AND ACQ.idServizio = ASSNZ.idServizio 
       AND ACQ.stato_allievo <> 'ritirato' 
    GROUP BY 
     ASSNZ.idServizio, 
     ASSNZ.idUtente 

стол "ASSNZ" имеет 213886 строк с индексом "idUtente", "idServizio"

стол "ACQ" имеет 8950 строки с индексом "idContatto", "idServizio"

ASSNZ таблицы:

CREATE TABLE `ciac_corsi_assenze` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `idUtente` int(11) DEFAULT NULL, 
    `idServizio` int(11) DEFAULT NULL, 
    `idCorso` int(11) DEFAULT NULL, 
    `idCalendario` int(11) DEFAULT NULL, 
    `modalita` varchar(255) DEFAULT NULL, 
    `ore` int(11) DEFAULT NULL, 
    `assenzeDidattiche` float DEFAULT NULL, 
    `assenzeAmministrative` float DEFAULT NULL, 
    `dataLezione` date DEFAULT NULL, 
    `ora_inizio` varchar(8) DEFAULT NULL, 
    `ora_fine` varchar(8) DEFAULT NULL, 
    `dataFineStage` date DEFAULT NULL, 
    `giustificata` varchar(128) DEFAULT NULL, 
    `motivazione` longtext, 
    `grouped` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `idUtente` (`idUtente`) USING BTREE, 
    KEY `idServizio` (`idServizio`) USING BTREE, 
    KEY `dataLezione` (`dataLezione`) USING BTREE 
) ENGINE=InnoDB AUTO_INCREMENT=574582 DEFAULT CHARSET=utf8; 

ПОЛУЧ таблицы:

CREATE TABLE `ciac_serviziacquistati_ita` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `idServizio` int(11) NOT NULL, 
    `idContatto` int(11) NOT NULL, 
    `idAzienda` int(11) NOT NULL, 
    `idSede` int(11) NOT NULL, 
    `tipoPersona` int(11) NOT NULL, 
    `num_registro` int(11) NOT NULL, 
    `codice` varchar(255) CHARACTER SET latin1 DEFAULT NULL, 
    `dal` date NOT NULL, 
    `al` date NOT NULL, 
    `ore` int(11) NOT NULL, 
    `costoOrario` decimal(10,0) NOT NULL, 
    `annoFormativo` varchar(128) CHARACTER SET latin1 NOT NULL, 
    `stato_attuale` int(11) NOT NULL, 
    `datore_attuale` int(11) NOT NULL, 
    `stato_allievo` varchar(64) CHARACTER SET latin1 NOT NULL DEFAULT 'corsista', 
    `data_ritiro` date DEFAULT NULL, 
    `crediti_formativi` int(11) NOT NULL, 
    `note` longtext CHARACTER SET latin1 NOT NULL, 
    `valore_economico` decimal(10,2) NOT NULL, 
    `dataInserimento` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    PRIMARY KEY (`id`), 
    KEY `idServizio` (`idServizio`) USING BTREE, 
    KEY `idAzienda` (`idAzienda`) USING BTREE, 
    KEY `idContatto` (`idContatto`) USING BTREE 
) ENGINE=InnoDB AUTO_INCREMENT=9542 DEFAULT CHARSET=utf8; 

это мой EXPLAIN из выбора

enter image description here

Теперь, так как запрос медленно, в течение 1.5s/2.0s ??

Что-то не так?

UPDATE

добавлен новый индекс (с ответом Джона Боллинджера) к таблице ciac_corsi_assenze:

PRIMARY KEY (`id`), 
    KEY `dataLezione` (`dataLezione`) USING BTREE, 
    KEY `test` (`idUtente`,`idServizio`) USING BTREE 
) ENGINE=InnoDB AUTO_INCREMENT=574582 DEFAULT CHARSET=utf8; 

добавлен новый индекс к таблице ciac_serviziAcquistati_ITA:

PRIMARY KEY (`id`), 
    KEY `idAzienda` (`idAzienda`) USING BTREE, 
    KEY `test2` (`idContatto`,`idServizio`) USING BTREE 
) ENGINE=InnoDB AUTO_INCREMENT=9542 DEFAULT CHARSET=utf8; 

Новый EXPLAIN :

enter image description here

Но это всегда медленно :(

+0

У меня когда-то была эта проблема, когда определения столбцов были разными. Столбцы, которые вы соединяете, это 'INT NOT NULL' на одной таблице и' INT DEFAULT NULL' на другой. Можете ли вы сделать определения столбцов одинаковыми? (Конечно, делайте это на тестовой таблице и/или db, а не на живых данных, если что-то пойдет не так) – charmeleon

+0

@charmeleon теперь определение столбцов одно и то же (INT NOT NULL). Но запрос всегда медленный – marcozipsp

+0

Насколько велика таблица 'ciac_corsi_assenze' vs' ciac_serviziacquistati_ita'? Похоже, что ваш запрос в основном выбирает каждую строку из 'ciac_corsi_assenze' (поскольку условие' WHERE' не существует). Если 'ciac_serviziacquistati_ita' значительно меньше таблицы, вы можете сначала« вывести »запрос из меньшей таблицы. – maresa

ответ

0

Ваши таблицы имеют отдельные индексы на различных колонках, представляющих интерес, но MySQL будет использовать только один индекс для каждой таблицы для выполнения запроса. Этот конкретный запрос, вероятно, будет вызван таблицей ciac_corsi_assenze, имеющей индекс на (idUtente, idServizio) (и такой индекс заменит существующий на (idUtente)). Это должно позволить MySQL избежать сортировки строк результатов для выполнения группировки, и это поможет больше в выполнении соединения, чем любой из существующих индексов.

Запрос, скорее всего, будет вызван таблицей ciac_serviziAcquistati_ITA с индексом на (idContatto, idServizio) или даже на (idContatto, idServizio, ritirato). Любой из них заменит существующий индекс только (idContatto).

+0

Спасибо, но не работал :(это всегда медленно – marcozipsp

+0

@marcozipsp, ваш запрос не очень сложный.Если он (сейчас) поддерживается наилучшими индексами, то единственной вероятной областью улучшения является усиление аппаратного обеспечения, на котором работает MySql. Быстрее диск (и убедитесь, что он * локальный * диск), больше памяти и меньше конфликтов для ЦП могут помочь. Но прежде чем рассматривать их, проверьте свой план запроса, чтобы убедиться, что используются новые индексы. –

+0

см. последнее обновление – marcozipsp

0

Джон пошел в правильном направлении. Однако порядок столбцов в составном индексе нуждается в изменении.

Для GROUP BY, этот порядок необходимо (на ASSNZ):

INDEX(idServizio, idUtente) 

(и что следует заменить KEY(idServizio), но не KEY(idUtente))

Тогда ACQ потребности, в следующем порядке:

INDEX(idContatto, idServizio, stato_allievo) 

замена только KEY(idContatto).