Performance et clause WHERE.. IN (SELECT ..).
Bonjour à tous,
Je travaille avec de gros volumes et je tente d'optimiser mes traitements.
Je pourrais intégrer le parallélisme dans mes traitements. Je pourrais aussi effectuer certaines "opérations hors base", en implémentant des algorithmes spéciaux, mais complexes..
Sur de gros volumes de données, je constate que la construction suivante est "colossalement contre-performante" :
Code:
UPDATE ... WHERE ... IN (SELECT ...);
Par exemple :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| DROP TABLE IF EXISTS `A`;
CREATE TABLE IF NOT EXISTS `A` (
`idA` INT NOT NULL AUTO_INCREMENT,
`value` INT NOT NULL,
PRIMARY KEY (`idA`)
)
ENGINE = InnoDB;
DROP TABLE IF EXISTS `B`;
CREATE TABLE IF NOT EXISTS `B` (
`idB` INT NOT NULL AUTO_INCREMENT,
`fk_idA` INT NOT NULL,
`value` INT NOT NULL,
PRIMARY KEY (`idB`),
INDEX `idfk_idA` (`fk_idA` ASC),
INDEX `idvalue` (`value` ASC)
)
ENGINE = InnoDB;
CREATE TEMPORARY TABLE `tmpTable`
SELECT `B`.`fk_idA` AS `idA`
FROM `B`
WHERE `B`.`value` > 3;
UPDATE `A`
SET `A`.`value` = 10
WHERE `A`.`idA` IN (SELECT `tmpTable`.`idA` AS `idA` FROM `tmpTable`); |
La procédure suivante s'exécute beaucoup plus rapidement :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| DELIMITER //
DROP PROCEDURE IF EXISTS myProc //
CREATE PROCEDURE myProc()
BEGIN
DECLARE n INT DEFAULT 0;
#- Indicateur de "fin de curseur".
DECLARE done INT DEFAULT 0;
#- Curseur sur les valeurs distinctes de `id_cdr`.
DECLARE updateCur CURSOR FOR SELECT `idA` AS `idA` FROM `tmpTable`;
#- Curseur de détection de fin de sélection.
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
#- On sélectionne les valeurs sur lesquelles on va travailler.
DROP TABLE IF EXISTS `tmpTable`;
CREATE TEMPORARY TABLE `tmpTable`
SELECT `B`.`fk_idA` AS `idA`
FROM `B`
WHERE `B`.`value` > 3;
#- Lancement de l'opération.
SET done = 0;
OPEN updateCur;
FETCH updateCur INTO n;
WHILE done = 0 DO
UPDATE `A`
SET `A`.`value` = 10
WHERE `A`.`idA`=n;
FETCH updateCur INTO n;
END WHILE;
CLOSE updateCur;
END //
DELIMITER ; |
Ce que je recherche à faire ressemble à un "UPDATE avec jointure" : UPDATE d'une table en fonction d'un critère calculé sur une autre table.
Quelqu'un connaît-il une procédure plus performante pour parvenir au même résultat?
Remarque :
Code:
Server version: 5.1.49-0.dotdeb.0 (Debian)
Merci à tous,
A+