2013-01-15 14 views
10

मेरे पास 2 मिलियन रिकॉर्ड्स के साथ एक डेटाबेस है और मुझे अपने वेब एप्लिकेशन पर दिखाने के लिए एक पेजिनेशन करने की आवश्यकता है, जिसमें DataGrid में प्रति पृष्ठ 10 रिकॉर्ड होना चाहिए।SQL सर्वर पर पेजिनेशन करने का सबसे अच्छा तरीका कौन सा है?

मैंने पहले से ही ROW_NUMBER() का उपयोग करने का प्रयास किया है, लेकिन इस तरह से सभी 2 मिलियन रिकॉर्ड का चयन करेंगे और फिर केवल 10 रिकॉर्ड प्राप्त होंगे। मैंने TOP 10 का उपयोग करने का भी प्रयास किया, लेकिन मुझे पृष्ठों को नियंत्रित करने के लिए पहली और अंतिम आईडी को सहेजना होगा। और मैंने पढ़ा है कि DataAdapter.Fill() का उपयोग करके सभी सामग्री का चयन किया जाएगा और फिर मुझे आवश्यक 10 रिकॉर्ड प्राप्त होंगे।

सबसे अच्छा तरीका कौन सा है? क्या मुझे DataAdapter.Fill() का उपयोग करना चाहिए? या SQL सर्वर के फ़ंक्शन ROW_NUMBER() का उपयोग करें? या TOP 10 का उपयोग करने का प्रयास करें?

+4

यह http://blog.sqlauthority.com/2010/12/15/sql-server-server-side-paging-in-sql-server-2011-a-better-alternative/ –

+0

बस इसे पढ़ें: http://www.asp.net/web-forms/tutorials/data-access/paging-and-sorting/efficiently-paging-through-large-amounts-of-data-vb यह एक बहुत ही पूर्ण ट्यूटोरियल है (VB.NET लेकिन इससे इस मामले में कोई फर्क नहीं पड़ता)। –

+0

@ गुइलहेम आप वास्तव में * एसक्यूएल-सर्वर -2000 का उपयोग कर रहे हैं? (टैग) यदि हां, तो यह आपके विकल्पों को काफी सीमित कर देगा। –

उत्तर

4
ALTER PROCEDURE [dbo].[SP_tblTest_SelectSpecificRecordsWithCTE] 
    @FromRow int = 1000000, 
    @PgSize int = 10 
AS 
BEGIN 
    ;WITH RecordsRN AS 
    (
     select ID, colValue, ROW_NUMBER() over(order by colvalue) as Num from tblTest 
    ) 
    SELECT ID Value, colValue Text FROM RecordsRN WHERE Num between @FromRow AND (@[email protected]) 
END 

यह क्वेरी है जो मैं पेजिंग के लिए उपयोग कर रहा हूं। इसका इस्तेमाल करें और आप 4-5 सेकंड में वांछित 10 रिकॉर्ड प्राप्त करेंगे। मुझे 3 सेकंड में 10 रिकॉर्ड मिल रहे हैं और मेरे डीबी में कुल रिकॉर्ड 10 मिलियन हैं, शीर्ष 10 का उपयोग न करें, यह हर बार केवल 10 रिकॉर्ड लाएगा। मेरे मामले में मैं पृष्ठ के आकार को बनाए रख रहा हूं और सत्र में पंक्ति संख्या (@FromRow) शुरू कर रहा हूं और मैं इन दो मानों को नीचे दी गई संग्रहीत प्रक्रिया में पास करता हूं और परिणाम प्राप्त करता हूं। और यदि आप SQL 2012 का उपयोग कर रहे हैं तो आप ऑफ़सेट का उपयोग करना चाहेंगे और अगले 10 पंक्तियों को प्राप्त कर सकते हैं। ऑफ़सेट कीवर्ड के बारे में Google पर खोजें और आप शीर्ष पर अपना वांछित परिणाम देखेंगे।

धन्यवाद

+0

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

1

मैं (स्वतः) उत्पन्न पृष्ठांकित सबक्वेरी के लिए निम्न पैटर्न का उपयोग करें:

  • उप एक प्रश्न धारणात्मक @skipN पंक्तियों छोड़ देता है और तब लेता है:

    इस पैटर्न पर
    select top (@takeN) <your-column-list> 
    from (
        select qSub2.*, _row=row_number() over (order by SomeColumn Asc, SomethingElse Desc) 
        from (
         select top (@takeN + @skipN) <your-column-list> 
         from ( 
          select <your-subquery-here> 
         ) as qSub1 
         order by SomeColumn Asc, SomethingElse Desc 
        ) as qSub2 
    ) qSub3 
    where _row > @skipN 
    order by _row 
    

    नोट्स अगली @takeN पंक्तियां।

  • यदि आपको परिणाम में अतिरिक्त कॉलम _row की परवाह नहीं है, तो आप <your-column-list>* के साथ प्रतिस्थापित कर सकते हैं; मैं स्पष्ट कॉलम सूची का उपयोग करता हूं क्योंकि यह मुझे रनटाइम पर कॉलम के सेट को सबसेट करने की अनुमति देता है जो उपयोगी हो सकता है। केवल प्राइम कुंजी कॉलम और पसंद के लिए।
  • आपका order by क्लॉज समान होना चाहिए; एसक्यूएल सर्वर का ऑप्टमाइज़र आमतौर पर समझने के लिए पर्याप्त स्मार्ट है। डुप्लिकेशंस top खंड का एक दुष्प्रभाव है जो परिणामों को कम करने के लिए उपयोग किया जाता है; top निरस्त सबक्वायरी पर कानूनी नहीं है। और शीर्ष क्वेरी-ऑप्टिमाइज़र को समझने में मदद करने के लिए उपयोगी है कि यह क्वेरी कुछ पंक्तियों को वापस करने की संभावना है।
  • पृष्ठ संख्या + आकार आधारित पैरामीटर के विपरीत @takeN और @skipN का उपयोग करने के कारण काफी मामूली हैं। सबसे पहले, यह थोड़ा अधिक लचीला और क्वेरी में थोड़ा सा सरल है, और दूसरी बात यह है कि यह सर्वर की शक्तियों को थोड़ा बेहतर बनाता है: डीबी विशेष रूप से इस तरह के प्रश्नों को अनुकूलित करने के बारे में शानदार नहीं है, और उम्मीद है कि इस तरह का एक बाहरी, सरल शीर्ष खंड ऑप्टिमाइज़र के लिए संभावित पंक्तियों की अधिकतम संख्या को समझने के लिए छोटा बनाता है। आम तौर पर, मैं एसक्यूएल में गणना करने से बचने की कोशिश करता हूं, मैं कोड में समान रूप से अच्छा कर सकता हूं क्योंकि यह ऑप्टिमाइज़र को भ्रमित करता है (हालांकि @ पेजकाउंट * के विशिष्ट मामले में @ पेजसाइज़ प्रयोग ने दिखाया है कि यह एक बड़ी समस्या नहीं है)

ध्यान दें कि एसक्यूएल सर्वर 2012 इस परिदृश्य के लिए एक नए offset...fetch clause का समर्थन करता है जो कि बहुत आसान है।

2

ROW_NUMBER() का उपयोग करें और एक स्थिर उपयोगिता फ़ंक्शन (मेरे कोड में GetPaginatedSQL के रूप में) लागू करें, जो स्वचालित रूप से आपके मूल SQL क्वेरी को सीमित/पृष्ठबद्ध में लपेटता है।

यह एक मैं का उपयोग करें:

namespace Persistence.Utils 
{ 
    public class SQLUtils 
    { 
     /// <summary> 
     /// Builds a paginated/limited query from a SELECT SQL. 
     /// </summary> 
     /// <param name="startRow">Start row</param> 
     /// <param name="numberOfRows">Number/quatity of rows to be expected</param> 
     /// <param name="sql">Original SQL (without its ordering clause)</param> 
     /// <param name="orderingClause">MANDATORY: ordering clause (including ORDER BY keywords)</param> 
     /// <returns>Paginated SQL ready to be executed.</returns> 
     /// <remarks>SELECT keyword of original SQL must be placed exactly at the beginning of the SQL.</remarks> 
     public static string GetPaginatedSQL(int startRow, int numberOfRows, string sql, string orderingClause) 
     { 
      // Ordering clause is mandatory! 
      if (String.IsNullOrEmpty(orderingClause)) 
       throw new ArgumentNullException("orderingClause"); 

      // numberOfRows here is checked of disable building paginated/limited query 
      // in case is not greater than 0. In this case we simply return the 
      // query with its ordering clause appended to it. 
      // If ordering is not spe 
      if (numberOfRows <= 0) 
      { 
       return String.Format("{0} {1}", sql, orderingClause); 
      } 
      // Extract the SELECT from the beginning. 
      String partialSQL = sql.Remove(0, "SELECT ".Length); 

      // Build the limited query... 
      return String.Format(
       "SELECT * FROM (SELECT ROW_NUMBER() OVER ({0}) AS rn, {1}) AS SUB WHERE rn > {2} AND rn <= {3}", 
       orderingClause, 
       partialSQL, 
       startRow.ToString(), 
       (startRow + numberOfRows).ToString() 
      ); 
     } 
    } 
} 

समारोह ऊपर सुधार किया जा सकता है, लेकिन एक प्रारंभिक कार्यान्वयन है।

फिर, अपने DAOs में, आप बस कुछ इस तरह कर रही किया जाना चाहिए:

using (var conn = new SqlConnection(CONNECTION_STRING)) 
{ 
    using (var cmd = conn.CreateCommand()) 
    { 
     String SQL = "SELECT * FROM MILLIONS_RECORDS_TABLE"; 
     String SQLOrderBy = "ORDER BY DATE ASC "; //GetOrderByClause(Object someInputParams); 
     String limitedSQL = GetPaginatedSQL(0, 50, SQL, SQLOrderBy); 

     DataSet ds = new DataSet(); 
     SqlDataAdapter adapter = new SqlDataAdapter(); 

     cmd.CommandText = limitedSQL; 

     // Add named parameters here to the command if needed... 

     adapter.SelectCommand = cmd; 
     adapter.Fill(ds); 

     // Process the dataset... 
    } 
    conn.Close(); 
} 

आशा है कि यह मदद करता है।

संबंधित मुद्दे