क्या मुझे पेजिंग के लिए LINQ's Skip()
और Take()
विधि का उपयोग करना चाहिए , या SQL क्वेरी के साथ अपने पेजिंग को लागू करना चाहिए ?
सबसे कुशल कौन सा है? मैं एक को दूसरे पर क्यों चुनूंगा?
मैं SQL Server 2008, ASP.NET MVC और LINQ का उपयोग कर रहा हूं।
क्या मुझे पेजिंग के लिए LINQ's Skip()
और Take()
विधि का उपयोग करना चाहिए , या SQL क्वेरी के साथ अपने पेजिंग को लागू करना चाहिए ?
सबसे कुशल कौन सा है? मैं एक को दूसरे पर क्यों चुनूंगा?
मैं SQL Server 2008, ASP.NET MVC और LINQ का उपयोग कर रहा हूं।
जवाबों:
यदि आप skip(n).take(m)
linq पर विधियों (SQL 2005/2008 डेटाबेस सर्वर के रूप में) के साथ अपने प्रश्न का संक्षिप्त उत्तर देने की कोशिश कर रहे हैं, तो आपकी क्वेरी Select ROW_NUMBER() Over ...
स्टेटमेंट का उपयोग कर रही होगी , किसी तरह SQL इंजन में प्रत्यक्ष पेजिंग है।
आपको एक उदाहरण देते हुए, मेरे पास एक db तालिका है जिसे mtcity
मैंने लिखा है और मैंने निम्नलिखित प्रश्न (काम के साथ-साथ संस्थाओं को linq के साथ) लिखा है:
using (DataClasses1DataContext c = new DataClasses1DataContext())
{
var query = (from MtCity2 c1 in c.MtCity2s
select c1).Skip(3).Take(3);
//Doing something with the query.
}
परिणामी क्वेरी होगी:
SELECT [t1].[CodCity],
[t1].[CodCountry],
[t1].[CodRegion],
[t1].[Name],
[t1].[Code]
FROM (
SELECT ROW_NUMBER() OVER (
ORDER BY [t0].[CodCity],
[t0].[CodCountry],
[t0].[CodRegion],
[t0].[Name],
[t0].[Code]) AS [ROW_NUMBER],
[t0].[CodCity],
[t0].[CodCountry],
[t0].[CodRegion],
[t0].[Name],
[t0].[Code]
FROM [dbo].[MtCity] AS [t0]
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]
जो कि एक विंडो डेटा एक्सेस है (बहुत शांत, btw cuz बहुत भीख माँगने के बाद से डेटा लौटाएगा और जब तक शर्तें पूरी होंगी तब तक टेबल तक पहुंच जाएगा)। यह बहुत समान होगा:
With CityEntities As
(
Select ROW_NUMBER() Over (Order By CodCity) As Row,
CodCity //here is only accessed by the Index as CodCity is the primary
From dbo.mtcity
)
Select [t0].[CodCity],
[t0].[CodCountry],
[t0].[CodRegion],
[t0].[Name],
[t0].[Code]
From CityEntities c
Inner Join dbo.MtCity t0 on c.CodCity = t0.CodCity
Where c.Row Between @p0 + 1 AND @p0 + @p1
Order By c.Row Asc
अपवाद के साथ, इस दूसरी क्वेरी को linq परिणाम की तुलना में तेजी से निष्पादित किया जाएगा क्योंकि यह डेटा एक्सेस विंडो बनाने के लिए विशेष रूप से इंडेक्स का उपयोग करेगा; इसका मतलब है, अगर आपको कुछ फ़िल्टरिंग की आवश्यकता है, तो Entity लिस्टिंग (जहां पंक्ति बनाई गई है) में फ़िल्टरिंग (या होनी चाहिए) और अच्छे प्रदर्शन को बनाए रखने के लिए कुछ अनुक्रमित भी बनाए जाने चाहिए।
अब, क्या बेहतर है?
यदि आपके पास अपने तर्क में बहुत अधिक ठोस वर्कफ़्लो हैं, तो उचित SQL तरीका लागू करना जटिल होगा। उस स्थिति में LINQ समाधान होगा।
यदि आप तर्क के उस हिस्से को सीधे SQL (एक संग्रहीत प्रक्रिया में) में कम कर सकते हैं, तो यह और भी बेहतर होगा क्योंकि आप मेरे द्वारा दिखाए गए दूसरी क्वेरी को लागू कर सकते हैं (अनुक्रमित का उपयोग करके) और SQL को निष्पादन योजना को बनाने और संग्रहीत करने की अनुमति देते हैं। क्वेरी (प्रदर्शन में सुधार)।
प्रयोग करके देखें
FROM [TableX]
ORDER BY [FieldX]
OFFSET 500 ROWS
FETCH NEXT 100 ROWS ONLY
SQL सर्वर में 501 से 600 तक पंक्तियों को प्राप्त करने के लिए, उन्हें मेमोरी में लोड किए बिना। ध्यान दें कि यह वाक्य रचना के साथ उपलब्ध हो गया है SQL सर्वर 2012 केवल
जबकि LINQ-to-SQL एक OFFSET
क्लॉज उत्पन्न करेगा (संभवतः ROW_NUMBER() OVER()
जैसा कि दूसरों ने उल्लेख किया है ) का उपयोग करते हुए , SQL में पेजिंग करने के लिए एक पूरी तरह से अलग, बहुत तेज़ तरीका है। इसे अक्सर इस ब्लॉग पोस्ट में वर्णित "तलाश विधि" कहा जाता है ।
SELECT TOP 10 first_name, last_name, score
FROM players
WHERE (score < @previousScore)
OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC
@previousScore
और @previousPlayerId
मूल्यों पिछले पृष्ठ से पिछले रिकॉर्ड के संबंधित मूल्यों कर रहे हैं। यह आपको "अगला" पृष्ठ लाने की अनुमति देता है। यदि ORDER BY
दिशा है ASC
, तो >
इसके बजाय बस का उपयोग करें ।
उपरोक्त विधि के साथ, आप पहले पिछले 40 रिकॉर्ड प्राप्त किए बिना तुरंत पृष्ठ 4 पर नहीं जा सकते। लेकिन अक्सर, आप वैसे भी कूदना नहीं चाहते हैं। इसके बजाय, आपको एक बहुत तेज़ क्वेरी मिलती है जो आपके अनुक्रमण के आधार पर निरंतर समय में डेटा लाने में सक्षम हो सकती है। साथ ही, आपके पृष्ठ "स्थिर" बने रहते हैं, इससे कोई फर्क नहीं पड़ता कि अंतर्निहित डेटा बदलता है (उदाहरण पृष्ठ 1 पर, जबकि आप पृष्ठ 4 पर हैं)।
उदाहरण के लिए, वेब अनुप्रयोगों में अधिक डेटा लोड करने में आलसी होने पर पेजिंग को लागू करने का यह सबसे अच्छा तरीका है।
ध्यान दें, "सीक विधि" को कीसेट पेजिंग भी कहा जाता है ।
LinqToSql स्वचालित रूप से एक .Skip (N1) .Take (N2) को आपके लिए TSQL सिंटैक्स में बदल देगा। वास्तव में, हर एक "क्वेरी" जो आप Linq में करते हैं, वास्तव में सिर्फ पृष्ठभूमि में आपके लिए एक SQL क्वेरी बना रहा है। इसका परीक्षण करने के लिए, जब आपका एप्लिकेशन चल रहा हो, तो बस SQL Profiler चलाएँ।
स्किप / टेक मेथडोलॉजी ने मेरे लिए बहुत अच्छा काम किया है, और अन्य जो मैंने पढ़ा है।
जिज्ञासा से बाहर, आपके पास किस प्रकार की स्व-पेजिंग क्वेरी है, जो आपको लगता है कि लिनक के स्किप / ले से अधिक कुशल है?
हम एक संग्रहीत प्रक्रिया के भीतर डायनेमिक SQL में लिपटे CTE (क्योंकि हमारे एप्लिकेशन को डायनेमिक सर्वर साइड के डायनेमिक सॉर्टिंग की आवश्यकता है) का उपयोग करते हैं। यदि आप चाहें तो मैं एक मूल उदाहरण प्रदान कर सकता हूं।
LINQ द्वारा निर्मित T / SQL को देखने का मुझे मौका नहीं मिला है। क्या कोई नमूना पोस्ट कर सकता है?
हम LINQ या तालिकाओं तक सीधी पहुंच का उपयोग नहीं करते हैं क्योंकि हमें सुरक्षा की अतिरिक्त परत की आवश्यकता होती है (गतिशील SQL इसे कुछ हद तक तोड़ दिया जाता है)।
कुछ इस तरह से करना चाहिए ट्रिक आप मापदंडों के लिए पैरामीटर किए गए मानों में जोड़ सकते हैं, आदि।
exec sp_executesql 'WITH MyCTE AS (
SELECT TOP (10) ROW_NUMBER () OVER ' + @SortingColumn + ' as RowID, Col1, Col2
FROM MyTable
WHERE Col4 = ''Something''
)
SELECT *
FROM MyCTE
WHERE RowID BETWEEN 10 and 20'
sp_executesql
आपके पास सुरक्षित तरीके से पैरामीटर पास करने की संभावना है, जैसे EXECUTE sp_executesql 'WITH myCTE AS ... WHERE Col4=@p1) ...', '@p1 nvarchar(max)', @ValueForCol4
:। इस संदर्भ में सुरक्षित होने का मतलब है कि यह SQL इंजेक्शन के खिलाफ मजबूत है - आप चर के अंदर हर संभव मूल्य पास कर सकते हैं @ValueForCol4
- यहां तक कि '--'
, और क्वेरी अभी भी काम करेगी!
SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN @CampoId = 1 THEN Id WHEN @CampoId = 2 THEN field2 END)
ROW_NUMBER() OVER()
ऑफसेट एमुलेशन की तुलना में बहुत तेज हो सकती है । इसे भी देखें: 4guysfromrolla.com/webtech/042606-1.shtml
SQL Server 2008 में:
DECLARE @PAGE INTEGER = 2
DECLARE @TAKE INTEGER = 50
SELECT [t1].*
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[COLUMNORDER] DESC) AS [ROW_NUMBER], [t0].*
FROM [dbo].[TABLA] AS [t0]
WHERE ([t0].[COLUMNS_CONDITIONS] = 1)
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN ((@PAGE*@TAKE) - (@TAKE-1)) AND (@PAGE*@TAKE)
ORDER BY [t1].[ROW_NUMBER]
T0 में सभी रिकॉर्ड्स हैं। t1 में केवल वे ही उस पृष्ठ के अनुरूप हैं
मैं जो दृष्टिकोण दे रहा हूं वह सबसे तेज़ पृष्ठांकन है जो SQL सर्वर प्राप्त कर सकता है। मैंने 5 मिलियन रिकॉर्ड पर यह परीक्षण किया है। यह दृष्टिकोण SQL सर्वर द्वारा उपलब्ध कराए गए "OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY" से कहीं बेहतर है।
-- The below given code computes the page numbers and the max row of previous page
-- Replace <<>> with the correct table data.
-- Eg. <<IdentityColumn of Table>> can be EmployeeId and <<Table>> will be dbo.Employees
DECLARE @PageNumber int=1; --1st/2nd/nth page. In stored proc take this as input param.
DECLARE @NoOfRecordsPerPage int=1000;
DECLARE @PageDetails TABLE
(
<<IdentityColumn of Table>> int,
rownum int,
[PageNumber] int
)
INSERT INTO @PageDetails values(0, 0, 0)
;WITH CTE AS
(
SELECT <<IdentityColumn of Table>>, ROW_NUMBER() OVER(ORDER BY <<IdentityColumn of Table>>) rownum FROM <<Table>>
)
Insert into @PageDetails
SELECT <<IdentityColumn of Table>>, CTE.rownum, ROW_NUMBER() OVER (ORDER BY rownum) as [PageNumber] FROM CTE WHERE CTE.rownum%@NoOfRecordsPerPage=0
--SELECT * FROM @PageDetails
-- Actual pagination
SELECT TOP (@NoOfRecordsPerPage)
FROM <<Table>> AS <<Table>>
WHERE <<IdentityColumn of Table>> > (SELECT <<IdentityColumn of Table>> FROM
@PageDetails WHERE PageNumber=@PageNumber)
ORDER BY <<Identity Column of Table>>
आप इस प्रदर्शन को और बेहतर बना सकते हैं
From CityEntities c
Inner Join dbo.MtCity t0 on c.CodCity = t0.CodCity
Where c.Row Between @p0 + 1 AND @p0 + @p1
Order By c.Row Asc
यदि आप इस तरह से इसका उपयोग करेंगे तो यह बेहतर परिणाम देगा:
From dbo.MtCity t0
Inner Join CityEntities c on c.CodCity = t0.CodCity
कारण: क्योंकि आप CityEntities टेबल पर क्लास का उपयोग कर रहे हैं जो MtCity में शामिल होने से पहले कई रिकॉर्ड को खत्म कर देगा, इसलिए 100% सुनिश्चित है कि यह प्रदर्शन को कई गुना बढ़ा देगा ...
वैसे भी रॉडरिगोल्प द्वारा उत्तर वास्तव में सहायक है।
धन्यवाद
@p0
और कहाँ @p1
से विशेष रूप से आते हैं
पेजइंडेक्स पास करके आप इस सरल तरीके से पेजिंग को लागू कर सकते हैं
Declare @PageIndex INT = 1
Declare @PageSize INT = 20
Select ROW_NUMBER() OVER ( ORDER BY Products.Name ASC ) AS RowNumber,
Products.ID,
Products.Name
into #Result
From Products
SELECT @RecordCount = COUNT(*) FROM #Results
SELECT *
FROM #Results
WHERE RowNumber
BETWEEN
(@PageIndex -1) * @PageSize + 1
AND
(((@PageIndex -1) * @PageSize + 1) + @PageSize) - 1
2008 में हम छोड़ें () का उपयोग नहीं कर सकते। ()
तरीका यह है:
var MinPageRank = (PageNumber - 1) * NumInPage + 1
var MaxPageRank = PageNumber * NumInPage
var visit = Visita.FromSql($"SELECT * FROM (SELECT [RANK] = ROW_NUMBER() OVER (ORDER BY Hora DESC),* FROM Visita WHERE ) A WHERE A.[RANK] BETWEEN {MinPageRank} AND {MaxPageRank}").ToList();