2009-02-14 14 views
111

मैं पेजिंग के लिए LINQ के Skip() और Take() विधि का उपयोग करना चाहिए, या एक SQL क्वेरी के साथ अपने ही पेजिंग को लागू लागू करने के लिए?कारगर तरीका पेजिंग

कौन सा सबसे कुशल है? मैं एक दूसरे पर क्यों चुनूँगा?

मैं SQL सर्वर 2008, एएसपी.नेट एमवीसी और LINQ का उपयोग कर रहा हूं।

+0

मुझे लगता है कि यह निर्भर करता है। आप किस ऐप पर काम कर रहे हैं? इसका किस प्रकार का भार होगा? – BuddyJoe

+0

इस उत्तर पर भी एक नज़र डालें: http: // stackoverflow।कॉम/ए/10639172/416996 –

+0

इसे भी देखें http://www.aspsnippets.com/Articles/Custom-Paging-in-ASP.Net-GridView-using-SQL- सर्वर-Stored-Procedure.aspx –

उत्तर

169

आप एक संक्षिप्त जवाब अपने संदेह को, यदि आप LINQ पर (एसक्यूएल 2005/2008 डेटाबेस सर्वर के रूप में) के साथ skip(n).take(m) तरीकों पर अमल आपकी क्वेरी देने के लिए कोशिश कर रहा होगा Select ROW_NUMBER() Over ... कथन का उपयोग करके, एसक्यूएल इंजन में किसी भी तरह से सीधे पेजिंग है।

आपको एक उदाहरण देते हुए मैं एक 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] 

जो एक खिड़की वाली डेटा पहुंच है (बहुत अच्छा, बीटीडब्ल्यू सीयूज बहुत शुरुआत के बाद से डेटा लौटाएगा और जब तक शर्तों को पूरा किया जाता है तब तक तालिका तक पहुंच जाएगा)। यह बहुत ही के समान होगा:

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 परिणाम की तुलना में तेजी निष्पादित किया जाएगा साथ

; इसका मतलब है, अगर आपको कुछ फ़िल्टरिंग की आवश्यकता है, तो फ़िल्टरिंग इकाई प्रविष्टि (जहां पंक्ति बनाई गई है) में होना चाहिए (या होना चाहिए) और अच्छे प्रदर्शन को बनाए रखने के लिए कुछ इंडेक्स भी बनाए जाने चाहिए।

अब, क्या बेहतर है?

आप अपने तर्क में काफी ठोस कार्यप्रवाह है, तो उचित एसक्यूएल तरह से लागू करने जटिल हो जाएगा। उस मामले में LINQ समाधान होगा।

यदि आप तर्क के उस हिस्से को सीधे एसक्यूएल (संग्रहीत प्रक्रिया में) में कम कर सकते हैं, तो यह बेहतर होगा क्योंकि आप दूसरी क्वेरी को लागू कर सकते हैं जो मैंने आपको दिखाया है (इंडेक्स का उपयोग करके) और एसक्यूएल को उत्पन्न और स्टोर करने की अनुमति दें क्वेरी की निष्पादन योजना (प्रदर्शन में सुधार)।

+2

अच्छा उत्तर - सामान्य तालिका अभिव्यक्ति पेजिंग करने का एक अच्छा तरीका है। –

+0

क्या आप मेरा प्रश्न देख सकते हैं (http://stackoverflow.com/questions/11100929/asp-net-mvc-webgrid-efficent-paging/11104822#comment14552347_11104822)? मैंने एक एसपी बनाया जो मैंने अपने ईडीएमएक्स में जोड़ा और इसे एक लिनक-टू-एंटिटीज क्वेरी में इस्तेमाल किया। – Misi

+2

+1, अच्छा जवाब, मैं आपको दूसरे उदाहरण – Cohen

5

LinqToSql अपने आप आपके लिए TSQL वाक्य विन्यास में एक .Skip (एन 1) .Take (एन 2) में परिवर्तित कर देंगे। वास्तव में, लिंकक में आप जो भी "क्वेरी" करते हैं, वास्तव में पृष्ठभूमि में आपके लिए एक SQL क्वेरी बना रहा है। इसका परीक्षण करने के लिए, बस अपना एप्लिकेशन चल रहा है, तो बस SQL ​​प्रोफाइलर चलाएं।

स्किप/टेक पद्धति ने मेरे लिए बहुत अच्छा काम किया है, और जो कुछ मैंने पढ़ा है उससे।

जिज्ञासा से बाहर

, स्वयं पेजिंग क्वेरी आप किस प्रकार की क्या ज़रूरत है, आपको लगता है कि और अधिक कुशल से Linq के छोड़/ले रहा है?

4

हम एक CTE गतिशील एसक्यूएल में लिपटे का उपयोग एक संग्रहीत प्रक्रिया के भीतर (हमारे आवेदन डेटा सर्वर साइड के गतिशील छंटाई की आवश्यकता है क्योंकि)। यदि आप चाहें तो मैं एक बुनियादी उदाहरण प्रदान कर सकता हूं।

मुझे LINQ उत्पन्न होने वाले टी/एसक्यूएल को देखने का मौका नहीं मिला है। क्या कोई नमूना पोस्ट कर सकता है?

हम LINQ या सीधे टेबल तक पहुंच का उपयोग नहीं करते हैं क्योंकि हमें सुरक्षा की अतिरिक्त परत की आवश्यकता होती है (गतिशील एसक्यूएल कुछ हद तक टूट जाता है)।

ऐसा कुछ ऐसा करना चाहिए। आप, आदि मापदंडों के लिए पैरामिट्रीकृत मूल्यों में जोड़ सकते हैं

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' 
+2

@ mrdenny - उदाहरण के लिए एक ** संकेत ** आपने प्रदान किया है: 'sp_executesql' के साथ आपके पास पैरामीटर को एक सुरक्षित तरीके से पास करने की संभावना है, उदाहरण के लिए:' EXECUTE sp_executesql 'myCTE AS के साथ ... जहां Col4 = @ p1) ... ',' @ पी 1 nvarchar (अधिकतम) ', @ ValueForCol4'। इस संदर्भ में सुरक्षित यह है कि यह एसक्यूएल इंजेक्शन के खिलाफ मजबूत है - आप वैरिएबल '@ ValueForCol4' - यहां तक ​​कि '' '' के भीतर हर संभव मूल्य को पारित कर सकते हैं, और क्वेरी अभी भी काम करेगी! – Matt

+1

@mrdenny हाय, बजाय क्वेरी श्रृंखलाबद्ध की हम कुछ इस तरह का उपयोग करें: '(मामला द्वारा आदेश जब @CampoId = 1 फिर आईडी जब @CampoId = 2 तब field2 अंत) का चयन ROW_NUMBER() से अधिक' – Ezequiel

+0

उत्पादन कर सकते हैं कि कुछ भयानक एसक्यूएल निष्पादन योजनाएं। – mrdenny

0

आप आगे के प्रदर्शन में सुधार कर सकते हैं, इस

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 

कारण: क्योंकि आप जहां प्रयोग कर रहे हैं सिटीइन्टिटीज टेबल पर कक्षा जो एमटीसीटी में शामिल होने से पहले कई रिकॉर्ड खत्म कर देगी, इसलिए 100% सुनिश्चित करें कि यह प्रदर्शन को कई गुना बढ़ाएगा ...

वैसे भी rodrigoelp i द्वारा जवाब वास्तव में सहायक है।

धन्यवाद

+0

मुझे संदेह है कि इस सलाह का उपयोग करके कोई प्रदर्शन प्रभाव होगा। इसके लिए कोई संदर्भ नहीं मिल रहा है लेकिन क्वेरी में आंतरिक शामिल क्रम वास्तविक जुड़ने के क्रम से भिन्न हो सकता है। उत्तरार्द्ध तालिका के आंकड़ों और संचालन लागत अनुमानों का उपयोग कर क्वेरी ऑप्टिमाइज़र द्वारा तय किया जाता है। –

+0

@ImreP: यह वास्तव में कुछ हद तक [खोज विधि, जिसे मैंने वर्णित किया है] के अनुरूप हो सकता है (http://stackoverflow.com/a/19609720/521799)। हालांकि, मुझे यकीन नहीं है कि '@ p0' और अधिक विशेष रूप से' @ p1' –

47

FROM [TableX] 
ORDER BY [FieldX] 
OFFSET 500 ROWS 
FETCH NEXT 100 ROWS ONLY 

का उपयोग कर 501 से एसक्यूएल सर्वर में से 600 पंक्तियां प्राप्त करने के लिए, उन्हें स्मृति में लोड किए बिना प्रयास करें। ध्यान दें कि यह वाक्य रचना SQL Server 2012 केवल

+0

से आता है, मुझे लगता है कि यह गलत है। एसक्यूएल प्रदर्शित 502-601 से पंक्तियां दिखाता है (जब तक कि आप शून्य-अनुक्रमण नहीं कर रहे हों?) – Smudge202

10

साथ उपलब्ध हो गया है LINQ-एसक्यूएल के लिए एक OFFSET खंड उत्पन्न करते हैं (संभवतः ROW_NUMBER() OVER()as others have mentioned का उपयोग कर नकल करते), वहाँ एक बिल्कुल अलग, बहुत तेजी से रास्ता एसक्यूएल में पेजिंग प्रदर्शन करने के लिए है। इसे अक्सर "खोज विधि" कहा जाता है जैसा कि this blog post here में वर्णित है।

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 पर हों)।

उदाहरण के लिए, वेब अनुप्रयोगों में आलसी लोडिंग के दौरान यह पेजिंग को लागू करने का सबसे अच्छा तरीका है।

नोट, "तलाश विधि" को keyset paging भी कहा जाता है।

1

एसक्यूएल सर्वर 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 में हैं ही नहीं पेज

0

आप गुजर PageIndex

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 
द्वारा इस सरल तरीके से पेजिंग लागू कर सकते हैं करने के लिए इसी होते हैं
संबंधित मुद्दे