10
votes

Pourquoi la requête LINQ à SQL suivante a-t-elle généré une sous-requête?

J'ai fait la requête suivante:

SELECT
[Limit1].[C1] as [C1]
[Limit1].[id] as [Id], 
[Limit1].[title] as [title], 
[Limit1].[price] as [price], 
[Limit1].[author]
FROM (SELECT TOP (50) 
             [Extent1].[id] as as [Id], 
             [Extent1].[title] as [title], 
             [Extent1].[price] as [price], 
             [Extent1].[author] as [author]
      FROM Books as [Extent1]
      WHERE [Extent1].[price] > 50
     ) AS [Limit1]


4 commentaires

Y avait-il une erreur impliquée?


Non, je viens de courir le SQL dans le profileur et était curieux pourquoi il génère une sous-requête.


Pourquoi crée-t-il la limite1 et l'étendue1, généralement Linq utilise T0 / T1, etc.


J'ai vu cela dans le profileur, l'étendue1 et la limite1 qui est.


5 Réponses :


0
votes

La sous-requête est générée à des fins de projection, il est plus logique lorsque vous sélectionnez plusieurs tables dans un seul objet anonyme, la requête extérieure est utilisée pour rassembler les résultats.

Essayez ce qui se passe avec quelque chose comme ceci: < / p> xxx


3 commentaires

Oui, je peux le voir se produire avec plusieurs tables, mais que voulez-vous dire par des fins de projection?


Les projections sont des choses comme: somme, max, min et aussi prendre ()


Ok, donc si je sortitais la prise, cela ne générerait probablement pas la sous-requête.



2
votes

Disclaimer: Je n'ai jamais utilisé Linq avant ...

Mon hypothèse serait un support de pagination? Je suppose que vous avez une sorte de prendre (50, 50) qui obtient 50 enregistrements, à partir de l'enregistrement 50. Jetez un coup d'œil à la SQL que la requête génère et vous constaterez probablement qu'il utilise un Structure de sous-requête pour lui permettre de renvoyer des 50 lignes dans une requête dans environ la durée de retour des 50 premières lignes.

Dans tous les cas, la sous-requête imbriquée n'ajouter aucune surcharge de performance car elle est optimisée automatiquement lors de la compilation du plan d'exécution.


4 commentaires

Oui, j'ai vérifié l'heure et c'est pratiquement la même chose, j'étais juste curieux de savoir pourquoi ils le font de cette façon quand il peut facilement être réalisé sans la sous-requête.


Juste pour le dossier, ce sera vraiment prendre (50) et sauter (50), et cela a eu l'intention de pagination, mais je pense vraiment que dans ce cas, c'est une question de savoir comment vous construisez l'expression.


Par intérêt, quelle est la requête que LINQ exécute si vous ignorez dites 100 rangées?


Avec la prise, comme prendre (50) .skip (100) ou comme une autre déclaration distincte ou sans la prise



0
votes

N'est-ce pas un cas de la première requête renvoyant le nombre total de lignes tandis que le second extrait le sous-ensemble des lignes en fonction de l'appel à la méthode .take ()?


3 commentaires

Ok, je vois ce que tu dis. La première requête LINQ génère la requête SQL extérieure et la liste = List.take.take (50) génère la sous-requête. Est-ce exact?


C'est ce que je pense, mais je ne l'ai pas essayé, alors je ne suis pas certain à 100%.


J'ai essayé exactement la même déclaration que ci-dessus et je reçois la sortie SQL souhaitée ..



1
votes

Vous pouvez toujours le rendre plus propre comme ceci:

SELECT TOP (50) [t0].[countryID], [t0].[regionID], [t0].[countryName], [t0].[code]
FROM [dbo].[countries] AS [t0]
WHERE [t0].[regionID] = @p0


3 commentaires

Oui, je l'ai fait plus propre, mais j'étais curieux pourquoi il génère une sous-requête avec la requête Linq que j'ai fournie. Est-ce parce que je fais la prise séparément?


Je pense que cette dernière ligne fait la différence ici: "Liste = list.take.take (50)", sa projetage elle-même puis en faisant la prise / en haut.


Mettez à jour mon message avec un autre exemple, où vous pouvez utiliser séparément. Prenez une requête propre.



0
votes
  1. Je suis d'accord avec @justin Swartsel. Il n'y avait aucune erreur en jeu, c'est donc en grande partie une affaire académique.
  2. LINQ-TO-SQL s'efforce de générer SQL que fonctionne efficacement (qu'il a fait dans votre cas).
    1. mais cela ne fait aucun effort pour générer classique sql qu'un humain créerait probablement.
    2. Les impléments LINQ-TO-SQL ont probablement utilisé le modèle de constructeur pour générer le SQL.
      1. Si tel est le cas, il serait plus facile d'ajouter une sous-chaîne (ou une sous-requête dans ce cas) qu'il ne serait pas de reculer et d'insérer un fragment «Top X» dans la clause SELECT.

2 commentaires

Donc, ce que vous dites, c'est que les concepteurs Linq où juste paresseux et il leur était plus facile de générer une sous-requête plutôt que de faire une top dans la première requête.


@XAaisoft: Si les implémentations utilisaient le modèle de constructeur et la sous-requête favorisée - ajoute aux "meilleurs inserts", ils l'ont probablement fait, car l'approche a donné un code robuste; Pas nécessairement parce que c'était plus facile.