【发布时间】:2021-06-16 14:23:20
【问题描述】:
我有一个超级慢的查询,不知道它为什么很慢,而且还有一些奇怪的行为。
SELECT <fields list>
FROM scadenze s
JOIN cartelle_cliniche cc ON (cc.id = s.id_cartella)
JOIN anagrafica a ON (a.id = cc.id_anagrafica)
JOIN scadenze_sedute ss ON (ss.id_scadenza = s.id)
JOIN pmultiple_prenotazioni pp ON (pp.id = ss.id_fisico OR pp.id = ss.id_virtuale)
LEFT JOIN medici_privati mp ON (mp.id = a.id_medico)
LEFT JOIN operatorif o ON (o.id = cc.id_operatore_emittente)
WHERE pp.confermato = '1' AND pp.annullato = '0'
AND pp.id_esito != 4 AND s.id_stato = '0'
AND (DATE(s.data_scadenza) BETWEEN '2021-06-01' AND '2021-06-16')
GROUP BY s.id, TIME(ss.data_seduta)
持续5分钟!!
现在,您可以看到有很多 JOIN 并且只有 5 个 WHERE 子句。 如果我从 WHERE 子句中删除这 3 个参数:pp.confermato = '1' AND pp.annullato = '0' AND pp.id_esito != 4,则查询仅持续 0.15 秒。 我在这 3 个参数上有单个索引,并且我还尝试使用 MySQL 的 FORCE INDEX 函数添加多个索引。但什么都没有。
如果我将这些参数放在 HAVING 子句中,例如:
SELECT <fields list>
FROM scadenze s
JOIN cartelle_cliniche cc ON (cc.id = s.id_cartella)
JOIN anagrafica a ON (a.id = cc.id_anagrafica)
JOIN scadenze_sedute ss ON (ss.id_scadenza = s.id)
JOIN pmultiple_prenotazioni pp ON (pp.id = ss.id_fisico OR pp.id = ss.id_virtuale)
LEFT JOIN medici_privati mp ON (mp.id = a.id_medico)
LEFT JOIN operatorif o ON (o.id = cc.id_operatore_emittente)
WHERE s.id_stato = '0' AND (DATE(s.data_scadenza) BETWEEN '2021-06-01' AND '2021-06-16')
GROUP BY s.id, TIME(ss.data_seduta)
HAVING pp.confermato = '1' AND pp.annullato = '0' AND pp.id_esito != 4
查询持续 0.15 秒。 但是在 WHERE 子句中使用这些参数有什么问题呢? (在 Have 子句中,我得到 308 条记录而不是 309 条)
如果我在该字段的任何一个上都有索引,什么会导致这个缓慢的查询?
提前谢谢你。
编辑:
在此处为 pmultiple_prenotazione (pp) 创建表:
CREATE TABLE `pmultiple_prenotazioni` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`id_utente` INT(11) NOT NULL,
`id_anagrafica` INT(11) NOT NULL DEFAULT '0',
`id_cartella` INT(11) NOT NULL DEFAULT '0',
`id_kit` INT(11) NOT NULL DEFAULT '0',
`id_fase` INT(11) NOT NULL DEFAULT '0',
`data_seduta` DATETIME NOT NULL,
`giorno` VARCHAR(50) NOT NULL COLLATE 'latin1_swedish_ci',
`id_reparto` INT(11) NOT NULL,
`importo_prestazione` DECIMAL(6,2) NOT NULL DEFAULT '0.00',
`peso_prestazione` DECIMAL(5,2) NOT NULL DEFAULT '0.00',
`durata_prestazione` SMALLINT(6) NOT NULL DEFAULT '0',
`id_operatore` INT(11) NOT NULL DEFAULT '0',
`solo` TINYINT(1) NOT NULL DEFAULT '0',
`confermato` TINYINT(1) NOT NULL DEFAULT '0',
`annullato` TINYINT(1) NOT NULL DEFAULT '0',
`id_esito` TINYINT(4) NOT NULL DEFAULT '0',
`creazione` DATETIME NOT NULL,
`univoco` VARCHAR(255) NULL DEFAULT NULL COLLATE 'latin1_swedish_ci',
PRIMARY KEY (`id`) USING BTREE,
INDEX `id_cartella` (`id_cartella`) USING BTREE,
INDEX `id_kit` (`id_kit`) USING BTREE,
INDEX `data_seduta` (`data_seduta`) USING BTREE,
INDEX `confermato` (`confermato`) USING BTREE,
INDEX `id_utente` (`id_utente`) USING BTREE,
INDEX `id_reparto` (`id_reparto`) USING BTREE,
INDEX `id_anagrafica` (`id_anagrafica`) USING BTREE,
INDEX `id_fase` (`id_fase`) USING BTREE,
INDEX `peso_prestazione` (`peso_prestazione`) USING BTREE,
INDEX `durata_prestazione` (`durata_prestazione`) USING BTREE,
INDEX `solo` (`solo`) USING BTREE,
INDEX `id_operatore` (`id_operatore`) USING BTREE,
INDEX `univoco` (`univoco`) USING BTREE,
INDEX `annullato` (`annullato`) USING BTREE,
CONSTRAINT `prenkit` FOREIGN KEY (`id_kit`) REFERENCES `starbene_1`.`pmultiple_kit` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
AUTO_INCREMENT=717
;
【问题讨论】:
-
当您提出查询优化问题时,请为查询中引用的每个表包含
SHOW CREATE TABLE的结果,这样我们就不必猜测您的表中的列、索引或约束.还包括每个查询的EXPLAIN的结果。 -
对不起,我按照你的建议添加了信息。
-
您在
scadenze_sedute.id_fisico和scadenze_sedute.id_virtuale上有索引吗? -
@slkorolev 是的,当然!没有 WHERE 子句,查询持续 0.15"
标签: mysql performance indexing query-optimization