পেজিং বাস্তবায়নের কার্যকর উপায়


118

পেজিংয়ের জন্য লিনকুইস Skip()এবং Take()পদ্ধতিটি ব্যবহার করা উচিত, বা এসকিউএল কোয়েরি দিয়ে আমার নিজস্ব পেজিং প্রয়োগ করা উচিত?

কোনটি সবচেয়ে দক্ষ? কেন আমি একজনকে অন্যের থেকে বেছে নেব?

আমি এসকিউএল সার্ভার ২০০৮, এএসপি.নেট এমভিসি এবং লিনকিউ ব্যবহার করছি।


আমি মনে করি এটি নির্ভর করে। আপনি কোন অ্যাপের উপর কাজ করছেন? এটি কি ধরনের বোঝা হবে?
বাডিজো

: পাশাপাশি এই উত্তরে দেখে নিন stackoverflow.com/a/10639172/416996
Õzbek

উত্তর:


175

আপনাকে আপনার সন্দেহের একটি সংক্ষিপ্ত উত্তর দেওয়ার চেষ্টা করা হচ্ছে, যদি আপনি skip(n).take(m)লিনাকের পদ্ধতিগুলি কার্যকর করেন (এসকিউএল 2005/2008 সাথে ডাটাবেস সার্ভার হিসাবে) আপনার ক্যোয়ারীটি Select ROW_NUMBER() Over ...বিবৃতিটি ব্যবহার করবে , এতে এসকিউএল ইঞ্জিনে কোনওভাবে সরাসরি পেজিং রয়েছে।

আপনাকে একটি উদাহরণ দেওয়ার জন্য, আমার কাছে একটি ডিবি টেবিল কল রয়েছে mtcityএবং আমি নিম্নলিখিত কোয়েরিটি লিখেছি (সত্তা থেকে লিনক সহ কাজ করুন):

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

ব্যতিক্রম ছাড়া, এই দ্বিতীয় ক্যোয়ারী লিনাক ফলাফলের চেয়ে দ্রুত কার্যকর করা হবে কারণ এটি ডেটা অ্যাক্সেস উইন্ডো তৈরি করতে একচেটিয়াভাবে সূচক ব্যবহার করবে; এর অর্থ, যদি আপনার কিছু ফিল্টারিংয়ের প্রয়োজন হয় তবে ফিল্টারিংটি সত্তা তালিকাতে (বা হওয়া আবশ্যক) হওয়া উচিত (যেখানে সারিটি তৈরি করা হয়) এবং ভাল সম্পাদন চালিয়ে যাওয়ার জন্য কিছু সূচি তৈরি করা উচিত।

এখন আর কি ভাল?

আপনার যুক্তিতে যদি যথেষ্ট শক্ত ওয়ারফ্লো থাকে তবে সঠিক এসকিউএল উপায় কার্যকর করা জটিল হবে। সেক্ষেত্রে লিনকিউই এর সমাধান হবে।

আপনি যদি লজিকের সেই অংশটি সরাসরি এসকিউএলে (সঞ্চিত পদ্ধতিতে) কম করতে পারেন তবে এটি আরও ভাল হবে কারণ আপনি যে দ্বিতীয় কোয়েরিটি আপনাকে দেখিয়েছেন তা প্রয়োগ করতে পারবেন (সূচকগুলি ব্যবহার করে) এবং এসকিউএলকে এক্সিকিউশন প্ল্যান উত্পন্ন এবং সঞ্চয় করতে পারবেন ক্যোয়ারী (কর্মক্ষমতা উন্নত))


2
দুর্দান্ত উত্তর - সাধারণ টেবিলের প্রকাশটি পেজিং করার একটি ভাল উপায়।
টেকনোলজি ডিক্সন

আপনি কি আমার প্রশ্নটি পরীক্ষা করতে পারবেন ( স্ট্যাকওভারফ্লো.com / প্রশ্নস 1111929/… )? আমি একটি এসপি তৈরি করেছি যা আমি আমার EDMX এ যুক্ত করেছি এবং এটি লিনাক টু-সত্তা কোয়েরিতে ব্যবহার করেছি।
মিসি

2
+1, ভাল উত্তর, আমি আপনাকে দ্বিতীয় উদাহরণটির পারফরম্যান্স সুবিধাগুলি ব্যাখ্যা করার জন্য প্রশংসা করি
কোহেন

@ জোহান: সিক পদ্ধতি নামে একটি বিকল্প রয়েছে যা বড় পৃষ্ঠা সংখ্যার জন্য অফসেটগুলিকে ভারী করে তোলে ।
লুকাশ এডার

50

ব্যবহার করার চেষ্টা করুন

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

এসকিউএল সার্ভারে 501 থেকে 600 পর্যন্ত সারিগুলি মেমরিতে লোড না করে পেতে। লক্ষ্য করুন এই সিনট্যাক্স সাথে উপলব্ধ পরিণত হয়েছে এসকিউএল সার্ভার 2012 শুধুমাত্র


আমি মনে করি এটি ভুল। এসকিউএল প্রদর্শিত 502-601 থেকে সারি দেখায় (আপনি যদি শূন্য-সূচক না হন?)
স্মুডজ202

না এটি 501 থেকে 600 পর্যন্ত সারিগুলি পায় না
ভোলকান সেন

12

যদিও লিনিক্যু-টু-এসকিউএল একটি OFFSETক্লজ তৈরি করবে (সম্ভবত ROW_NUMBER() OVER() অন্যরা উল্লিখিতভাবে ব্যবহার করে অনুকরণ করা হবে ), এসকিউএল-এ পেজিং করার সম্পূর্ণ ভিন্ন উপায় রয়েছে। এখানে এই ব্লগ পোস্টে বর্ণিত হিসাবে এটি প্রায়শই "পদ্ধতি পদ্ধতি" বলা হয় ।

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 পৃষ্ঠায় আপনি পৃষ্ঠায় রয়েছেন)।

উদাহরণস্বরূপ, ওয়েব অ্যাপ্লিকেশনগুলিতে অলস বেশি ডেটা লোড করার সময় পেজিং বাস্তবায়নের সেরা উপায়।

দ্রষ্টব্য, "সন্ধান পদ্ধতি" কে কীসেট পেজিংও বলা হয় ।


5

লিনকটোসকিউএল আপনার জন্য স্বয়ংক্রিয়ভাবে একটি .স্কিপ (এন 1) .টেক (এন 2) টিএসকিউএল সিনট্যাক্সে রূপান্তর করবে। প্রকৃতপক্ষে, লিনক-এ আপনি করেন এমন প্রতিটি "ক্যোয়ারী" আসলে আপনার জন্য ব্যাকগ্রাউন্ডে একটি এসকিউএল কোয়েরি তৈরি করছে। এটি পরীক্ষা করতে, আপনার অ্যাপ্লিকেশন চলমান অবস্থায় কেবল এসকিউএল প্রোফাইলার চালান।

স্কিপ / টেক পদ্ধতিটি আমার এবং অন্যেরা যা পড়ে তা থেকে খুব ভালভাবে কাজ করে।

কৌতূহলের বাইরে আপনার কী ধরণের স্ব-পেজিং ক্যোয়ারী রয়েছে, আপনি বিশ্বাস করেন যে লিন্কের এড়িয়ে যাওয়া / নেওয়া তার চেয়ে বেশি দক্ষ?


4

আমরা সঞ্চিত পদ্ধতির মধ্যে ডায়নামিক এসকিউএলে আবৃত একটি সিটিই ব্যবহার করি (কারণ আমাদের অ্যাপ্লিকেশনটির ডেটা সার্ভারের দিকের গতিশীল বাছাই করা প্রয়োজন)। আপনি চাইলে আমি একটি প্রাথমিক উদাহরণ সরবরাহ করতে পারি।

আমার কাছে টিএন / এসকিউএল দেখার সুযোগ নেই যা লিনিকিউ উত্পাদন করে। কেউ কি নমুনা পোস্ট করতে পারেন?

আমাদের সুরক্ষার অতিরিক্ত স্তর (গতিশীল এসকিউএল কিছুটা ভেঙে দেওয়া হয়েছে) হিসাবে আমরা টেবিলগুলিতে লিনকিউ বা সরল অ্যাক্সেস ব্যবহার করি না।

এর মতো কিছুতে কৌশলটি করা উচিত। আপনি প্যারামিটার ইত্যাদির জন্য প্যারামিটারাইজড মানগুলিতে যোগ করতে পারেন etc.

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 'WITH myCTE AS ... WHERE Col4=@p1) ...', '@p1 nvarchar(max)', @ValueForCol4। এই প্রসঙ্গে সুরক্ষিত করার অর্থ এটি এসকিউএল ইঞ্জেকশনের বিরুদ্ধে শক্ত - আপনি ভেরিয়েবলের অভ্যন্তরে প্রতিটি সম্ভাব্য মান পাস করতে পারেন @ValueForCol4- এমনকি '--'অনুসন্ধানটি এখনও কার্যকর হবে!
ম্যাট

1
@ মির্দেনি হাই, ক্যোয়ারীটি শোনানোর পরিবর্তে আমরা এরকম কিছু ব্যবহার করি: SELECT ROW_NUMBER() OVER (ORDER BY CASE WHEN @CampoId = 1 THEN Id WHEN @CampoId = 2 THEN field2 END)
এজেকুইল

এটি কিছু ভয়ঙ্কর এসকিউএল এক্সিকিউশন পরিকল্পনা তৈরি করতে পারে।
mrdenny

@ এমআরডেনি: বৃহত পৃষ্ঠাগুলির জন্য, সন্ধানের পদ্ধতিটিROW_NUMBER() OVER() অফসেট এমুলেশনের চেয়ে অনেক দ্রুত হতে পারে । আরও দেখুন: 4guysfromrolla.com/webtech/042606-1.shtml
লুকাশ এডার

2

এসকিউএল সার্ভার ২০০৮ এ:

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 এ সমস্ত রেকর্ড টি 1 তে কেবল সেই পৃষ্ঠাটির সাথে সম্পর্কিত are


2

আমি যে পন্থাটি দিচ্ছি তা হ'ল এসকিউএল সার্ভারটি অর্জন করতে পারে এমন দ্রুততম পৃষ্ঠা ination আমি এটি 5 মিলিয়ন রেকর্ডে পরীক্ষা করেছি। এই পদ্ধতিটি এসকিউএল সার্ভার দ্বারা সরবরাহিত "অফফুট 10 রাউস ফ্যাচ নেক্সট 10 সারি কেবল" এর চেয়ে অনেক ভাল।

-- 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>>

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% নিশ্চিত যে এটি কার্য সম্পাদনকে বহুগুণ বাড়িয়ে দেবে ...

যাইহোক রডরিগেল্পের উত্তর সত্যই সহায়ক।

ধন্যবাদ


আমি সন্দেহ করি এই পরামর্শটি ব্যবহার করে কোনও কার্যকারিতা প্রভাব ফেলবে। এর জন্য কোনও রেফারেন্স খুঁজে পাচ্ছে না তবে কোয়েরিতে অভ্যন্তরীণ যোগদানের ক্রমটি আসল যোগদানের ক্রম থেকে পৃথক হতে পারে। পরবর্তীটির সারণীর পরিসংখ্যান এবং অপারেশন ব্যয়ের অনুমান ব্যবহার করে ক্যোয়ারী অপ্টিমাইজার দ্বারা সিদ্ধান্ত নেওয়া হয়।
ইম্রে পহভেল

@ImreP এই শক্তি আসলে কিছুটা মিলা পদ্ধতি চাইতে, আমি বর্ণিত আছে । যদিও, আমি নিশ্চিত না কোথা থেকে @p0এবং আরও সুনির্দিষ্টভাবে @p1এসেছে
লুকাশ এডার

0

আপনি পেজইন্ডেক্সটি পাস করার মাধ্যমে এই সহজ পদ্ধতিতে পেজিং বাস্তবায়ন করতে পারেন

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

0

২০০৮ সালে আমরা স্কিপ () ব্যবহার করতে পারি না Take নিন ()

উপায়টি হ'ল:

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();
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.