Dois-je utiliser la méthode LINQ Skip()
et Take()
pour la pagination, ou implémenter ma propre pagination avec une requête SQL?
Quel est le plus efficace? Pourquoi choisirais-je l'un plutôt que l'autre?
J'utilise SQL Server 2008, ASP.NET MVC et LINQ.
sql
sql-server
asp.net-mvc
linq-to-sql
pagination
Cœur de pierre
la source
la source
Réponses:
Si vous essayez de vous donner une brève réponse à votre doute, si vous exécutez les
skip(n).take(m)
méthodes sur linq (avec SQL 2005/2008 comme serveur de base de données), votre requête utilisera l'Select ROW_NUMBER() Over ...
instruction, avec en quelque sorte une pagination directe dans le moteur SQL.En vous donnant un exemple, j'ai une table db appelée
mtcity
et j'ai écrit la requête suivante (fonctionne également avec linq aux entités):La requête résultante sera:
Ce qui est un accès aux données fenêtré (plutôt cool, btw cuz retournera des données depuis le tout début et accédera à la table tant que les conditions sont remplies). Ce sera très similaire à:
Sauf que, cette deuxième requête sera exécutée plus rapidement que le résultat linq car elle utilisera exclusivement l'index pour créer la fenêtre d'accès aux données; cela signifie que si vous avez besoin d'un filtrage, le filtrage doit être (ou doit être) dans la liste des entités (où la ligne est créée) et certains index doivent également être créés pour maintenir les bonnes performances.
Maintenant, quoi de mieux?
Si vous avez un flux de travail assez solide dans votre logique, la mise en œuvre de la méthode SQL appropriée sera compliquée. Dans ce cas, LINQ sera la solution.
Si vous pouvez réduire cette partie de la logique directement en SQL (dans une procédure stockée), ce sera encore mieux car vous pouvez implémenter la deuxième requête que je vous ai montrée (à l'aide d'index) et permettre à SQL de générer et de stocker le plan d'exécution du requête (amélioration des performances).
la source
Essayez d'utiliser
pour obtenir les lignes de 501 à 600 dans le serveur SQL, sans les charger en mémoire. Notez que cette syntaxe est devenue disponible avec SQL Server 2012 uniquement
la source
Bien que LINQ-to-SQL génère une
OFFSET
clause (éventuellement émulée en utilisantROW_NUMBER() OVER()
comme d'autres l'ont mentionné ), il existe un moyen entièrement différent et beaucoup plus rapide d'effectuer la pagination en SQL. Ceci est souvent appelé la «méthode de recherche» comme décrit dans cet article de blog ici .Les valeurs
@previousScore
et@previousPlayerId
sont les valeurs respectives du dernier enregistrement de la page précédente. Cela vous permet de récupérer la page "suivante". Si laORDER BY
direction estASC
, utilisez simplement à la>
place.Avec la méthode ci-dessus, vous ne pouvez pas passer immédiatement à la page 4 sans avoir d'abord récupéré les 40 enregistrements précédents. Mais souvent, vous ne voulez pas sauter aussi loin de toute façon. Au lieu de cela, vous obtenez une requête beaucoup plus rapide qui peut être en mesure de récupérer des données en temps constant, en fonction de votre indexation. De plus, vos pages restent «stables», peu importe si les données sous-jacentes changent (par exemple à la page 1, pendant que vous êtes à la page 4).
C'est le meilleur moyen d'implémenter la pagination lors du chargement différé de plus de données dans des applications Web, par exemple.
Notez que la "méthode de recherche" est également appelée pagination de jeu de clés .
la source
LinqToSql convertira automatiquement un .Skip (N1) .Take (N2) dans la syntaxe TSQL pour vous. En fait, chaque "requête" que vous faites dans Linq, est en fait juste la création d'une requête SQL pour vous en arrière-plan. Pour tester cela, exécutez simplement SQL Profiler pendant que votre application est en cours d'exécution.
La méthodologie skip / take a très bien fonctionné pour moi et pour d'autres d'après ce que j'ai lu.
Par curiosité, quel type de requête d'auto-pagination avez-vous, que vous croyez plus efficace que le saut / prise de Linq?
la source
Nous utilisons un CTE enveloppé dans Dynamic SQL (car notre application nécessite un tri dynamique du côté serveur de données) au sein d'une procédure stockée. Je peux vous donner un exemple de base si vous le souhaitez.
Je n'ai pas eu l'occasion d'examiner le T / SQL produit par LINQ. Quelqu'un peut-il publier un échantillon?
Nous n'utilisons pas LINQ ou un accès direct aux tables car nous avons besoin d'une couche de sécurité supplémentaire (étant donné que le SQL dynamique casse quelque peu cela).
Quelque chose comme ça devrait faire l'affaire. Vous pouvez ajouter des valeurs paramétrées pour les paramètres, etc.
la source
sp_executesql
vous avez la possibilité de passer des paramètres de manière sécurisée, par exemple:EXECUTE sp_executesql 'WITH myCTE AS ... WHERE Col4=@p1) ...', '@p1 nvarchar(max)', @ValueForCol4
. Sécurisé dans ce contexte signifie qu'il est robuste contre l'injection SQL - vous pouvez passer toutes les valeurs possibles à l'intérieur de la variable@ValueForCol4
- même'--'
, et la requête fonctionnera toujours!SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN @CampoId = 1 THEN Id WHEN @CampoId = 2 THEN field2 END)
ROW_NUMBER() OVER()
l'émulation de décalage. Voir aussi: 4guysfromrolla.com/webtech/042606-1.shtmlDans SQL Server 2008:
Dans t0 sont tous les enregistrements dans t1 sont seulement ceux correspondant à cette page
la source
L'approche que je donne est la pagination la plus rapide que le serveur SQL puisse réaliser. J'ai testé cela sur 5 millions de disques. Cette approche est bien meilleure que «OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY» fourni par SQL Server.
la source
vous pouvez encore améliorer les performances, vérifiez ceci
si vous utilisez from de cette manière, cela donnera un meilleur résultat:
raison: parce que vous utilisez la classe where sur la table CityEntities qui éliminera de nombreux enregistrements avant de rejoindre le MtCity, donc 100% sûr que cela augmentera les performances de plusieurs fois ...
Quoi qu'il en soit, la réponse de rodrigoelp est vraiment utile.
Merci
la source
@p0
et plus particulièrement@p1
proviennent deVous pouvez implémenter la pagination de cette manière simple en transmettant PageIndex
la source
En 2008, nous ne pouvons pas utiliser Skip (). Take ()
Le chemin est:
la source