Laissez-moi vous donner un peu de configuration. Nous avons une table InnoDB sur MySQL 5.1 avec près de 20 millions d'enregistrements, pas de clés étrangères et des index appropriés pour les requêtes que nous faisons. Nous utilisons la dernière version 6.3.5 MySQL pour le Cadre d'entité .NET. Normalement, nous sommes à utiliser pour traiter avec SQL Server et le cadre d'entité, mais sur ce projet, nous avons décidé de donner à MySQL un essai.
J'ai des théories sur la question mais laissez-moi d'abord faire la configuration du code
requête EF LINQ
var failsForAcct1001 = db.Failures.Where(x => x.AccountId == 1001);
/* farther down and later on in the code */
return failsForAcct1001.OrderBy(x => x.FailureId).Take(50);
code MySQL généré
Veuillez ignorer les noms de colonne qu'ils ne sont pas nessisaires pour comprendre le problème
select
External1.FailureId,
External1.col2,
External1.col3,
from (select
Inner1.FailureId,
Inner1.col2,
Inner1.col3,
from Failures Inner1
where External1.AccountId = 1001
) External1
order by External1.FailureId
limit 50
Ce SQL étant généré est très similaire à ce qui se passe dans SQL Server et SQL le gère avec un problème. Et ce n'est pas simplement une question de cadre d'entité, lorsque je prends cette requête et exécutez-la dans MySQL Workbench, cela est également expiré. Cependant, la requête suivante revient en moins d'une demi-seconde.
select
External1.FailureId,
External1.col2,
External1.col3,
from Failures External1
where External1.AccountId = 1001
order by External1.FailureId
limit 50
Je suppose que ce problème de performance a à voir avec le fait que MySQL essaie d'exécuter la requête interne qui retire tous les enregistrements de la base de données, puis essaie de trier et de prendre 50, au lieu de le faire tout comme une seule opération comme la deuxième requête Est-ce que.
Je veux vraiment juste confirmer mes observations et demander s'il y a quelque chose que je peux faire pour obtenir la première instruction SQL à exécuter plus rapidement, sans modifier de quelque manière que ce soit.
Étape 1 - Obtenez un expliquer le plan , en particulier EXPLAIN EXTENDED
vous montrera ce que SQL l'optimiseur de requête a réellement généré. peut-être Les index supplémentaires aideront - mais si vous "externalisez" votre génération SQL, vous êtes vraiment à la merci de tout ce qui était plus facile pour le développeur ORM, pas Quel était le mieux pour votre application. Une autre chose que vous pourriez essayer est en mémoire TEMP DB , car cela peut aider avec des sortes et des tables dérivées, que vous avez ...
Mariahb 5.3 peut gérer de telles requêtes.
L'optimisation est couverte par le commutateur optimizer_switch='derived_merge=on'
Dans la version 5.3.2 en cours, et cette optimisation deviendra défaut (aucun réglage nécessaire) dans la version imminente 5.3.3
Je sais que les requêtes LINQ sont composables, mais avez-vous essayé de jouer avec l'ordre des opérations LINQ pour voir si cela pourrait affecter le générateur de requêtes? Cette question peut être mieux servie sur le débordement de la pile.
var failsForAcct1001 = db.Failures.Where(x => x.AccountId == 1001).OrderBy(x => x.FailureId).Take(50);
Votre problème est dû à la sous-requête.
Il y a deux problèmes avec ceci: