2008-12-17 7 views
0

J'ai une question de sélection sql fondamentalement que les gens m'ont donné des réponses différentes au cours des années. Dites que j'ai quelques tables conçues chacune avec plus de 40 colonnes et potentiellement tiendra dix et des milliers de rangées, j'utilise SqlServer2005.Base de données et souci de performance EF?

En adhérant à ces tables, dans la clause where si j'ai des choses comme

select * from t1, t2 
where t1.UserID = 5 
and t1.SomeID = t2.SomeOtherID 

certaines personnes disent que vous devriez avoir alwasys la constante « t1.UserID = 5 » à l'avant et non après la « t1. SomeID = t2.SomeOtherID ", cela booste la performance de sélection. Alors que d'autres disent que cela n'a pas d'importance.

Quelle est la bonne réponse?

De même, si j'utilise ADO.NET Entity Framework pour implémenter ma DAL, la modélisation de tables comportant plus de 40 colonnes et effectuant des opérations CRUD sera-t-elle un problème de performance?

Merci,

Ray.

Répondre

4

En général, avec l'optimisation de base de données, vous devez d'abord écrire SQL qui est conceptuellement correct, puis ajuster les performances si le profilage le montre nécessaire. Lors d'une jointure interne, il est préférable d'utiliser SQL-92, INNER JOIN explicites que les produits cartésiens. Je voudrais donc commencer par écrire votre SQL comme suit:

SELECT * 
FROM t1 
    INNER JOIN t2 
    ON t1.SomeID = t2.SomeOtherID 
WHERE 
    t1.UserID = 5 

Le t1.SomeID = t2.SomeOtherID qui va dans la partie sur la INNER JOIN, car il exprime la relation entre les deux tables. L'ID utilisateur qui va dans la clause WHERE parce que c'est un filtre pour limiter le jeu de résultats. Écrire votre SQL de cette manière donne plus d'informations à l'optimiseur de base de données, car il exprime vos intentions sur la jointure par rapport au filtrage.

Maintenant, si vous n'obtenez pas des performances acceptables avec cette syntaxe dans une base de données réelle, alors n'hésitez pas à expérimenter avec déplacer des bits autour. Mais comme je l'ai dit, commencez par quelque chose qui est conceptuellement correct. En ce qui concerne la deuxième partie de votre question, l'implication de performance la plus évidente est que lorsque vous sélectionnez une collection d'entités, Entity Framework doit ramener toutes les propriétés pour les entités qu'elle matérialise. Donc, si vous avez 40 colonnes, vous récupérerez ces données sur le réseau, si vous les matérialisez en tant qu'entités. Il est cependant possible d'écrire des requêtes LINQ qui renvoient des types anonymes contenant uniquement les colonnes dont vous avez besoin. Cependant, pour faire CRUD complet, vous devrez retourner les entités.

1

Je sais que cette réponse est un peu banale, mais je suggère d'écrire des tests de performance. Préparez une application de console et testez-la vous-même. Exécutez la requête quelques centaines de fois et voyez combien de temps cela prend pour chaque chemin.

Il y a beaucoup de superstition en ce qui concerne les performances et l'optimisation des requêtes SQL. Certaines personnes font des choses en pensant que c'est plus rapide, mais elles ne vérifient pas leurs faits. En outre, la manière dont EF ou LinqToSql fonctionnent et interagissent avec la base de données peut introduire des différences de performances non évidentes dans SQL.

Si vous optimisez du code, vous pouvez également utiliser un profileur comme RedGate ANTS. Ce n'est pas gratuit, mais cela peut aider à trouver des goulots d'étranglement dans votre code. Ensuite, vous pouvez trouver des endroits dans votre code pour optimiser beaucoup plus facilement. Ce n'est pas toujours votre base de données qui ralentit vos applications. Ou parfois, vous exécutez une requête rapide, mais en le faisant un millier de fois lorsque vous pouvez mettre en cache le résultat.

2

L'opinion des gens à ce sujet va changer au fil du temps parce que l'optimisation des requêtes RDBMS a évolué au fil du temps, et différents SGBDR auront des approches différentes. Je ne peux pas parler pour tous les systèmes, mais il est vraiment improbable que cela fasse une différence en 2008. YMMV si vous êtes intéressé uniquement par un système spécifique.

Je peux vous dire que pour toute version récente d'Oracle, cela ne fait aucune différence.

0

Tout d'abord, construisez la requête en utilisant une syntaxe JOIN explicite, plutôt que le produit cartésien. Cela ne fera probablement aucune différence sur le plan des performances pour les optimiseurs modernes, mais cela rend l'information sur la façon dont les JOIN fonctionnent plus facilement pour les programmeurs.


SELECT Player.Name, Game.Date 
FROM Player 
    INNER JOIN Game ON Game.WinnerPlayerID = Player.PlayerID 
WHERE Game.WinnerFrags > Game.TotalFrags/2 
ORDER BY Player.Name 

qui nous donnera tous les joueurs triés par nom qui ont prendre plus de frags dans un jeu que tous les autres joueurs dans le jeu mis en place, et les dates des jeux. Mettre les deux conditions dans le JOIN n'affectera probablement pas non plus les performances, puisque l'optimiseur fait probablement le filtrage dans le cadre de JOIN. Cela commence cependant à importer pour les JOINs GAUCHE. Disons que nous cherchons combien de jeux les dix meilleurs joueurs de la semaine ont jamais gagné de la marge décrite ci-dessus. Comme il est possible que certains d'entre eux n'en aient jamais autant spectaculairement, nous aurons besoin de LEFT JOIN.


SELECT Player.WeekRank, Player.Name, COUNT(Game.*) AS WhitewashCount 
FROM Player 
    LEFT JOIN Game ON Game.WinnerPlayerID = Player.PlayerID 
WHERE Player.WeekRank >= 10 
    AND Game.WinnerFrags > Game.TotalFrags/2 
GROUP BY Player.WeekRank, Player.Name 
ORDER BY Player.WeekRank 

Eh bien, pas tout à fait. Le JOIN retournera des enregistrements pour chaque partie jouée par un joueur, ou les données de joueur et les données de jeu NULL si le joueur n'a joué à aucun jeu. Ces résultats seront filtrés, pendant ou après le JOIN en fonction de la décision de l'optimiseur, en fonction des critères de fragmentation. Cela permettra d'éliminer tous les enregistrements qui ne répondent pas aux critères de fragmentation. Il n'y aura donc pas de records à regrouper pour les joueurs qui n'ont jamais eu une victoire aussi spectaculaire. Créer efficacement une INNER JOIN .... FAIL.


SELECT Player.WeekRank, Player.Name, COUNT(Game.*) AS WhitewashCount 
FROM Player 
    LEFT JOIN Game ON Game.WinnerPlayerID = Player.PlayerID 
    AND Game.WinnerFrags > Game.TotalFrags/2 
WHERE Player.WeekRank >= 10 
GROUP BY Player.WeekRank, Player.Name 
ORDER BY Player.WeekRank 

Une fois que nous déplaçons les critères frag dans la jointure de la requête se comportera correctement, le retour des dossiers pour tous les joueurs dans les dix premiers de la semaine, indépendamment du fait qu'ils ont obtenu un lait de chaux.

Après tout cela, la réponse courte est:

Pour les situations INNER JOIN il n'a probablement pas à la différence de performance où vous mettez les conditions. Les requêtes sont plus lisibles si vous séparez les conditions de jointure et de filtrage. Et obtenir une condition au mauvais endroit peut sérieusement gâcher les résultats d'un LEFT JOIN.

Questions connexes