2010-10-01 5 views
0

Je vais avoir des problèmes avec certaines performances des requêtes, j'ai les 2 tableaux suivants:problème de performances des requêtes

CREATE TABLE `customers` (
    `CustFullName` varchar(45) NOT NULL, 
    `CustPassword` varchar(45) NOT NULL, 
    `CustEmail` varchar(128) NOT NULL, 
    `SocialNetworkId` tinyint(4) NOT NULL, 
    `CustUID` varchar(64) CHARACTER SET ascii NOT NULL, 
    `CustMoney` bigint(20) NOT NULL DEFAULT '0', 
    `LastIpAddress` varchar(45) CHARACTER SET ascii NOT NULL, 
    `LastLoginTime` datetime NOT NULL DEFAULT '1900-10-10 10:10:10', 
    `SmallPicURL` varchar(120) CHARACTER SET ascii DEFAULT '', 
    `LargePicURL` varchar(120) CHARACTER SET ascii DEFAULT '', 
    `LuckyChips` int(10) unsigned NOT NULL DEFAULT '0', 
    `AccountCreationTime` datetime NOT NULL DEFAULT '2009-11-11 11:11:11', 
    `AccountStatus` tinyint(4) NOT NULL DEFAULT '1', 
    `CustLevel` int(11) NOT NULL DEFAULT '0', 
    `City` varchar(32) NOT NULL DEFAULT '', 
    `State` varchar(32) NOT NULL DEFAULT '0', 
    `Country` varchar(32) NOT NULL DEFAULT '', 
    `Zip` varchar(16) CHARACTER SET ascii NOT NULL, 
    `CustExp` bigint(20) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`CustUID`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 

Et:

CREATE TABLE `mutualfriends` (
    `CustUID` varchar(32) CHARACTER SET ascii NOT NULL, 
    `CustUID2` varchar(32) CHARACTER SET ascii NOT NULL, 
    `FType` tinyint(4) NOT NULL, 
    PRIMARY KEY (`CustUID`,`CustUID2`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 
Table

clients contient des lignes 1M et mutalfriends environ 50k lignes.

J'ai besoin des résultats de la requête suivante:

SELECT c.CustUID, c.CustFullName, c.CustMoney, c.SmallPicURL 
FROM `customers` c 
WHERE c.`CustUID` = '9:2' 
OR c.`CustUID` IN 
(SELECT m.CustUID2 FROM mutualfriends m WHERE m.CustUID = '9:2'); 
OR c.`CustUID` IN 
(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2'); 

pour une raison que je ne comprends pas, cette requête prend environ 10 secconds pour terminer. Les sous requêtes ne contient pas plus de 3 lignes chacun, si je mets des constantes au lieu de:

(SELECT m.CustUID2 FROM mutualfriends m WHERE m.CustUID = '9:2'); 

Et:

(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2'); 

Par exemple:

SELECT c.CustUID, c.CustFullName, c.CustMoney, c.SmallPicURL 
    FROM `customers` c 
    WHERE c.`CustUID` = '9:2' 
    OR c.`CustUID` IN 
    ('9:3','9:4','9:5'); 
    OR c.`CustUID` IN 
    ('9:6','9:7'); 

Ensuite, la requête prend un quelques ms pour finir. Qu'est-ce que je fais mal ici cette requête ne devrait pas prendre plus de quelques ms ...

aussi je peux ajouter que cette partie de la requête:

(SELECT m.CustUID2 FROM mutualfriends m WHERE m.CustUID = '9:2'); 
(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2'); 

prend aussi quelques ms ..

Répondre

0

Il ya un certain nombre de pages sur le net qui vous dira comment optimiser les requêtes, mais ma première supposition est que MySQL n'utilise pas l'index sur mutualfriends car il est composé de deux colonnes.

+0

Je ne pense pas parce que cette ligne prend seulement quelques ms: (SELECT m.CustUID2 DE mutualfriends m OÙ m.CustUID = '9: 2'); –

0

Regardez http://dev.mysql.com/doc/refman/5.0/en/using-explain.html. Une recherche google rapide reviendra également avec beaucoup de points de départ pour gérer les optimisations SQL. La plupart s'appuient sur EXPLAIN cependant, alors commencez là.

En ce qui concerne votre requête, CustUID2 déclenchera une analyse de table complète, car elle n'est pas directement indexée. Veillez également à utiliser des sous-requêtes, car j'ai rencontré certains cas où l'optimiseur n'a pas pu optimiser complètement la sous-requête ... dans mon cas, il suffisait de diviser la requête en plusieurs requêtes (sans sous-requêtes) . Il peut également être utile d'utiliser JOIN car ils sont gérés différemment des sous-requêtes.

0

Quelques suppositions au hasard:

(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2'); 

... est probablement pas en mesure d'utiliser l'index (CustUID, CustUID2) efficacement. Vous devez vérifier le plan d'explication. Dans le cas contraire, pensez à ajouter un autre index uniue (CustUID2, CustUID).

expressions comme

WHERE <constant> 
    OR <subquery> 

... génère un plan merdique dans Oracle. Peut-être que c'est aussi le cas pour MySQL? Il peut généralement être résolu en travaillant d'une façon ou d'une autre l'expression constante dans la sous-requête ou en reformulant un peu la logique.

Une autre idée consiste à effectuer trois requêtes et à les assembler. Dans le cas où vous attendez beaucoup de lignes à retourner, cette option est moins attrayante car le tri va tuer les performances.

select * 
    from customer 
where CustUID = '9:2' 
union 
select * 
    from customer 
where CustUID in(select m.CustUID from mutualfriends m where m.CustUID2 = '9:2') 
union 
select * 
    from customer 
where CustUID in(select m.CustUID2 from mutualfriends m where m.CustUID = '9:2') 
Questions connexes