Question

La requête suivante est bloquée: (bien que les sous-requêtes effectuées séparément conviennent)

Je ne sais pas comment faire en sorte que le tableau d'explication ait l'air correct. Si quelqu'un me le dit, je vais le nettoyer.

select
sum(grades.points)) as p,  
from assignments 
left join grades using (assignmentID) 
where gradeID IN 

(select grades.gradeID 
from assignments 
left join grades using (assignmentID) 
where ... grades.date <= '1255503600' AND grades.date >= '984902400' 
group by     assignmentID order by grades.date DESC);

Je pense que le problème vient de la table des premières notes ... le type ALL avec autant de lignes semble en être la cause .. Tout est indexé.

J'ai téléchargé le tableau en tant qu'image. Impossible d'obtenir le bon formatage: http://imgur.com/AjX34.png

Un intervenant voulait la clause complète où:

explain extended select count(assignments.assignmentID) as asscount, sum(TRIM(TRAILING '-' FROM grades.points)) as p, sum(assignments.points) as t 
from assignments left join grades using (assignmentID) 
where gradeID IN 
(select grades.gradeID from assignments left join grades using (assignmentID) left join as_types on as_types.ID = assignments.type 
where assignments.classID = '7815' 
and (assignments.type = 30170 ) 
and grades.contactID = 7141 
and grades.points REGEXP '^[-]?[0-9]+[-]?' 
and grades.points != '-' 
and grades.points != '' 
and (grades.pointsposs IS NULL or grades.pointsposs = '') 
and grades.date <= '1255503600' 
AND grades.date >= '984902400' 
group by assignmentID 
order by grades.date DESC);
Était-ce utile?

La solution

Supposons que vous utilisiez une base de données Real (c'est-à-dire une base de données autre que MySQL, mais j'utiliserai Postgres comme exemple) pour effectuer cette requête:

SELECT * FROM ta WHERE aid IN (SELECT subquery)

une base de données réelle va examiner la sous-requête et estimer son nombre de lignes:

  • Si le nombre de lignes est petit (disons, moins de quelques millions)

Il exécuterait la sous-requête, puis créerait un hachage d'identifiants en mémoire, ce qui les rendait également uniques, ce qui est une fonctionnalité de IN ().

Ensuite, si le nombre de lignes extraites de ta est une petite partie de ta, il utilisera un index approprié pour extraire les lignes. Ou, si une partie importante de la table est sélectionnée, elle la scannera entièrement et consultera chaque identifiant dans le hachage, ce qui est très rapide.

  • Si toutefois le nombre de lignes de la sous-requête est assez grand

La base de données la réécrirait probablement en tant que jointure par fusion, en ajoutant un sort + unique à la sous-requête.

Cependant, vous utilisez MySQL. Dans ce cas, cela ne fera rien (il va ré-exécuter la sous-requête pour chaque ligne de votre table) donc cela prendra 1000 ans. Désolé.

Autres conseils

Voir "La lenteur insupportable de IN": http://www.artfulsoftware.com/infotree/queries.php#568

Super désordonné, mais: (merci pour l'aide de tout le monde)

   SELECT * 
   FROM grades
   LEFT JOIN assignments ON grades.assignmentID = assignments.assignmentID
   RIGHT JOIN (

   SELECT g.gradeID
 FROM assignments a
 LEFT JOIN grades g
 USING ( assignmentID ) 
 WHERE a.classID =  '7815'
 AND (
 a.type =30170
 )
 AND g.contactID =7141
  g.points
 REGEXP  '^[-]?[0-9]+[-]?'
 AND g.points !=  '-'
 AND g.points !=  ''
 AND (
 g.pointsposs IS NULL 
 OR g.pointsposs =  ''
 )
 AND g.date <=  '1255503600'
 AND g.date >=  '984902400'
 GROUP BY assignmentID
 ORDER BY g.date DESC
 ) AS t1 ON t1.gradeID = grades.gradeID

Si votre sous-requête fonctionne correctement lorsqu'elle est exécutée séparément, essayez d'utiliser un JOIN plutôt qu'un IN, comme ceci:

select count(assignments.assignmentID) as asscount, sum(TRIM(TRAILING '-' FROM grades.points)) as p, sum(assignments.points) as t 
from assignments left join grades using (assignmentID) 
join
(select grades.gradeID from assignments left join grades using (assignmentID) left join as_types on as_types.ID = assignments.type 
where assignments.classID = '7815' 
and (assignments.type = 30170 ) 
and grades.contactID = 7141 
and grades.points REGEXP '^[-]?[0-9]+[-]?' 
and grades.points != '-' 
and grades.points != '' 
and (grades.pointsposs IS NULL or grades.pointsposs = '') 
and grades.date <= '1255503600' 
AND grades.date >= '984902400' 
group by assignmentID 
order by grades.date DESC) using (gradeID);

Il n’ya vraiment pas assez d’informations pour répondre à votre question et vous avez placé une ... au milieu de la clause where, ce qui est étrange. Quelle est la taille des tables et quels sont les index?

Cela dit, s’il ya trop de termes dans une clause in, vous constaterez des performances sérieusement dégradées. Remplacez l'utilisation de in par une jointure droite .

Pour commencer, la table as_types de la clause in n'est pas utilisée. Rester connecté ne sert à rien, alors débarrassez-vous-en.

Cela laisse la clause in contenant uniquement la table des affectations et des notes de la requête externe. Il est clair que les assignations de modification wherees appartiennent à la clause where de la requête externe. Vous devez déplacer tous les éléments where grades = que ce soit dans la clause on de la jointure gauche vers les grades.

La requête est un peu difficile à suivre, mais je soupçonne que la sous-requête n’est pas du tout nécessaire. Il semble que votre requête soit fondamentalement la suivante:

SELECT FOO()
FROM assignments LEFT JOIN grades USING (assignmentID)  
WHERE gradeID IN 
(
SELECT grades.gradeID
FROM assignments LEFT JOIN grades USING (assignmentID)  
WHERE your_conditions = TRUE
);

Mais vous ne faites rien de vraiment chic dans la clause where de la sous-requête. Je soupçonne quelque chose de plus semblable à

SELECT FOO()
FROM assignments LEFT JOIN grades USING (assignmentID)  
GROUP BY groupings
WHERE your_conditions_with_some_tweaks = TRUE;

fonctionnerait aussi bien.

S'il me manque un peu de logique clé ici, veuillez commenter et je vais modifier / supprimer ce message.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top