2013-09-02 5 views
0

Je sais qu'il peut être difficile d'optimiser cette requête sans la table db, mais je suis un débutant et ne me fais confiance, il faut beaucoup de temps pour excuser cela comme 50 secondes et je ne peux pas penser à un autre façon de le faire, tout semble longlente SQL requête d'optimisation,

des conseils sont les bienvenus pour faire de ce plus rapidement

SELECT SUM(x) AS d 

FROM  (SELECT COUNT(*) AS x 
      FROM (SELECT DISTINCT id 
        FROM streamsignature 
        WHERE time < '2013-01-03' 
        AND signature = 'v' 
        AND signaturelevel = 'check' 
     ) AS subq 

INNER JOIN files    ON subq.id = files.id 
INNER JOIN filedata fm  ON files.id = fm.id 
INNER JOIN filetag v   ON files.id = v.id 
INNER JOIN filetype ft  ON files.id = ft.id 

LEFT JOIN definitiondata dd ON files.id = dd.id 

WHERE ( (NOT filename LIKE '%abc2%' AND filename LIKE '%abc%') 
     OR ( filename LIKE '%abc2%' AND fm.dset = 1   )) 
    AND v.type BETWEEN 0 and 4 
    AND v.length BETWEEN 3 and 7 
    AND v.decoder = 1 
    AND v.lighting = 'bright' 
    AND NOT vmd.time = 'xx:xx:Xx' 
    AND ft.country = 'IQ' 

UNION 

      i have a bunch of them like 4 with different conditions and 
      stuff 
+1

Pourquoi les jointures sont-elles si nombreuses? Est-ce que votre architecture l'exige? Avez-vous des index sur vos champs? – user1759572

+0

ouais j'ai besoin de ces jointures coz je dois correspondre à ces valeurs de différentes tables, aussi pas tous les attributs sont indexés dans le db – trackmeifUcan

+2

@ user2708115 S'il vous plaît afficher le résultat de 'EXPLAIN SELECT ... ' et les structures de table (vous pouvez obtenir les avec la commande 'SHOW CREATE TABLE tablename' – fancyPants

Répondre

2

Je ne comprends pas quelque chose au sujet de votre requête, je ne sais pas si je suis missunderstanding mais:

(SELECT COUNT(*) AS x 
      FROM (SELECT DISTINCT id 
        FROM streamsignature 
        WHERE time < '2013-01-03' 
        AND signature = 'v' 
        AND signaturelevel = 'check' 
     ) AS subq 

INNER JOIN files    ON subq.id 

est le nombre de lignes l'id de la table des fichiers? Comme vous, sur votre clause de jointure ont

ON subq.id = files.id 

Et le seul champ sélectionné est x, et il est le nombre de lignes

... Quoi qu'il en soit

Je pense plus comme des problèmes d'index. Vous devriez vraiment utiliser EXPLAIN pour savoir quels index sont manquants.

Par exemple:

EXPLAIN SELECT * FROM orderdetails d 
INNER JOIN orders o ON d.orderNumber = o.orderNumber 
INNER JOIN products p ON p.productCode = d.productCode 
INNER JOIN productlines l ON p.productLine = l.productLine 
INNER JOIN customers c on c.customerNumber = o.customerNumber 
WHERE o.orderNumber = 10101G 

exécution de cette requête produira:

********************** 1. row ********************** 
      id: 1 
    select_type: SIMPLE 
     table: l 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 7 
     Extra: 
********************** 2. row ********************** 
      id: 1 
    select_type: SIMPLE 
     table: p 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 110 
     Extra: Using where; Using join buffer 
********************** 3. row ********************** 
      id: 1 
    select_type: SIMPLE 
     table: c 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 122 
     Extra: Using join buffer 
********************** 4. row ********************** 
      id: 1 
    select_type: SIMPLE 
     table: o 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 326 
     Extra: Using where; Using join buffer 
********************** 5. row ********************** 
      id: 1 
    select_type: SIMPLE 
     table: d 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 2996 
     Extra: Using where; Using join buffer 
5 rows in set (0.00 sec)` 

Si vous regardez le résultat ci-dessus, vous pouvez voir tous les symptômes d'une mauvaise requête. Mais même si j'ai écrit une meilleure requête, les résultats seraient toujours les mêmes puisqu'il n'y a pas d'index. Le type de jointure est indiqué comme "ALL" (ce qui est le pire), ce qui signifie que MySQL n'a pas pu identifier les clés qui peuvent être utilisées dans la jointure et par conséquent les potentielles et les clés sont nulles. Plus important encore, la colonne rows montre que MySQL analyse tous les enregistrements de chaque table pour la requête. Cela signifie que pour exécuter la requête, il va scanner 7 × 110 × 122 × 326 × 2996 = 91 750 822 240 enregistrements pour trouver les quatre résultats correspondants. C'est vraiment horrible, et cela ne va qu'augmenter exponentiellement à mesure que la base de données se développe.

Maintenant, ajoutons des index évidents, tels que des clés primaires pour chaque table, et réexécutons la requête. En règle générale, vous pouvez considérer les colonnes utilisées dans les clauses JOIN de la requête comme de bons candidats pour les clés car MySQL analysera toujours ces colonnes pour trouver les enregistrements correspondants.

ALTER TABLE customers 
    ADD PRIMARY KEY (customerNumber); 
ALTER TABLE employees 
    ADD PRIMARY KEY (employeeNumber); 
ALTER TABLE offices 
    ADD PRIMARY KEY (officeCode); 
ALTER TABLE orderdetails 
    ADD PRIMARY KEY (orderNumber, productCode); 
ALTER TABLE orders 
    ADD PRIMARY KEY (orderNumber), 
    ADD KEY (customerNumber); 
ALTER TABLE payments 
    ADD PRIMARY KEY (customerNumber, checkNumber); 
ALTER TABLE productlines 
    ADD PRIMARY KEY (productLine); 
ALTER TABLE products 
    ADD PRIMARY KEY (productCode), 
    ADD KEY (buyPrice), 
    ADD KEY (productLine); 
ALTER TABLE productvariants 
    ADD PRIMARY KEY (variantId), 
    ADD KEY (buyPrice), 
    ADD KEY (productCode); 

Laissez libre cours à re-de la même requête à nouveau après avoir ajouté les index et le résultat devrait ressembler à ceci:

********************** 1. row ********************** 
      id: 1 
    select_type: SIMPLE 
     table: o 
     type: const 
possible_keys: PRIMARY,customerNumber 
      key: PRIMARY 
     key_len: 4 
      ref: const 
     rows: 1 
     Extra: 
********************** 2. row ********************** 
      id: 1 
    select_type: SIMPLE 
     table: c 
     type: const 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: const 
     rows: 1 
     Extra: 
********************** 3. row ********************** 
      id: 1 
    select_type: SIMPLE 
     table: d 
     type: ref 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 4 
      ref: const 
     rows: 4 
     Extra: 
********************** 4. row ********************** 
      id: 1 
    select_type: SIMPLE 
     table: p 
     type: eq_ref 
possible_keys: PRIMARY,productLine 
      key: PRIMARY 
     key_len: 17 
      ref: classicmodels.d.productCode 
     rows: 1 
     Extra: 
********************** 5. row ********************** 
      id: 1 
    select_type: SIMPLE 
     table: l 
     type: eq_ref 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 52 
      ref: classicmodels.p.productLine 
     rows: 1 
     Extra: 
5 rows in set (0.00 sec) 

Après l'ajout d'index, le nombre d'enregistrements numérisés a été ramené à 1 × 1 × 4 × 1 × 1 = 4. Cela signifie que pour chaque enregistrement avec orderNumber 10101 dans la table orderdetails, MySQL a pu trouver directement l'enregistrement correspondant dans toutes les autres tables en utilisant les index et n'a pas eu besoin de scanner l'ensemble table.

+0

http://dev.mysql.com/doc/refman/5.5/fr/execution-plan-information.html – JGutierrezC

0

il est assez difficile de répondre à cette question suffisamment bien car il n'y a pas assez de détails de fond dans la question. Cependant, en regardant la requête certains de ces points peut vous aider:

  • Essayez et effectuer moins jointures
  • Évitez d'utiliser LIKE requêtes avec un préfixe générique et le suffixe (ie '% chose%) - il sera résulter en un balayage de table complet, quelque chose qui va paralyser les performances s'il y a un grand nombre de lignes
  • Essayez et évitez les sous-sélections. Ils ne sont pas toujours un problème, mais ils pourraient être le signe d'aborder la question de la mauvaise façon
  • Utilisez le Explain syntax pour comprendre où vous pourriez manquer des indices importants

Bonne chance!

+0

+ essayez de voir l'indexation va vous aider (grandes tables - gros index lents, si ça ne correspond pas à la mémoire) – user1759572