অফসেট / ফেচ নেক্সট থেকে মোট সারির গণনা পাওয়া


92

সুতরাং, আমি একটি ফাংশন পেয়েছি যা আমার ওয়েবসাইটের জন্য পেজিং বাস্তবায়ন করতে চাই এমন অনেকগুলি রেকর্ড ফিরিয়ে দেয়। আমার কাছে পরামর্শ দেওয়া হয়েছিল যে এটি সম্পাদন করার জন্য আমি এসকিউএল সার্ভার ২০১২-এ অফসেট / ফেচ নেক্সটটি ব্যবহার করি। আমাদের ওয়েবসাইটে, আমাদের এমন একটি অঞ্চল রয়েছে যা মোট রেকর্ডের তালিকা এবং সেই সময়ে আপনি কোন পৃষ্ঠায় রয়েছেন তা তালিকাভুক্ত করে।

এর আগে, আমি পুরো রেকর্ড সেটটি পেয়েছিলাম এবং সেই অগ্রগতিতে পেজিংটি তৈরি করতে সক্ষম হয়েছি। তবে কেবলমাত্র FETCH NEXT X ROWS এর মাধ্যমে এসকিউএল উপায়টি ব্যবহার করে, আমি কেবল এক্স সারিগুলি ফিরে পেয়েছি, সুতরাং আমার মোট রেকর্ড সেটটি কী এবং আমার নূন্যতম এবং সর্বাধিক পৃষ্ঠাগুলি কীভাবে গণনা করতে হবে তা আমি জানি না। এটি করার একমাত্র উপায়টি হ'ল ফাংশনটি দু'বার কল করা এবং প্রথমটিতে একটি সারি গণনা করা, তারপরে FETCH NEXT সহ দ্বিতীয়টি চালানো। এর চেয়ে আরও ভাল উপায় আছে যে আমাকে দুবার কোয়েরি চালাতে না পারে? আমি পারফরম্যান্স গতি বাড়ানোর চেষ্টা করছি, এটিকে কম করবেন না।

উত্তর:


115

আপনি ব্যবহার করতে পারেন COUNT(*) OVER()... এখানে ব্যবহার করে একটি দ্রুত উদাহরণ sys.all_objects:

DECLARE 
  @PageSize INT = 10, 
  @PageNum  INT = 1;

SELECT 
  name, object_id, 
  overall_count = COUNT(*) OVER()
FROM sys.all_objects
ORDER BY name
  OFFSET (@PageNum-1)*@PageSize ROWS
  FETCH NEXT @PageSize ROWS ONLY;

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


44
৩,৫০০,০০০ রেকর্ড সহ একটি সারণীতে, COUNT (*) ওভার () 1 মিনিট 3 সেকেন্ড সময় নিয়েছিল। জেমস মোবার্গের নীচে বর্ণিত পদ্ধতির একই ডেটা-সেটটি পুনরুদ্ধার করতে 13 সেকেন্ড সময় নিয়েছে। আমি নিশ্চিত যে কাউন্ট ওভার পদ্ধতিটি ছোট ডেটা-সেটগুলির জন্য দুর্দান্ত কাজ করে তবে আপনি যখন বড় হওয়া শুরু করেন তখন তা যথেষ্ট গতিবেগ হয়।
ম্যাঠো 1460

অথবা আপনি কেবল COUNT (1) ওভার () খুব দ্রুত ব্যবহার করতে পারেন যেহেতু এটি টেবিল থেকে আসল ডেটা যেমন পড়তে হয় না, যেমন গণনা (*)
ldx

4
@ অ্যারনবার্ট্রান্ড সত্যিই? এর অর্থ অবশ্যই আপনার অবশ্যই একটি সূচক রয়েছে যাতে সমস্ত কলাম অন্তর্ভুক্ত রয়েছে, বা 2008R2 সাল থেকে এটি অনেক উন্নত হয়েছে। এই সংস্করণে, গণনা (*) ক্রমানুসারে কাজ করে, যার অর্থ প্রথম * (যেমন: সমস্ত কলাম) নির্বাচিত, তারপরে গণনা করা হয়। আপনি যদি একটি গণনা করেন (1), আপনি কেবল একটি ধ্রুবক নির্বাচন করুন যা আসল ডেটা পড়ার চেয়ে অনেক দ্রুত।
ldx

4
@ আইডিএক্স না, দুঃখিত, ২০০৮ আর 2-তে এটি কীভাবে কাজ করে নি sorry আমি .5.৫ থেকে এসকিউএল সার্ভার ব্যবহার করছি এবং আমি এমন একটি সময় মনে করতে পারি না যখন ইঞ্জিন কেবলমাত্র (()) বা COUNT (1) উভয়ের সংকীর্ণ সূচকটি স্ক্যান করার জন্য যথেষ্ট স্মার্ট ছিল না। অবশ্যই 2000 সালের পরে নয়। তবে হেই, আমার ২০০৮ আর 2 এর একটি উদাহরণ রয়েছে, আপনি কি এসকিউএলফিডালে একটি প্রতিস্থাপন সেট আপ করতে পারেন যা আপনার দাবি করা এই পার্থক্যটি প্রমাণ করে? আমি চেষ্টা করে খুশি।
অ্যারন বার্ট্র্যান্ড 11

4
২০০ s-এর সিক্যুয়াল সার্ভারে একটি ডেটাবেলে প্রায় 25 মিলিয়ন সারি দিয়ে একটি টেবিল অনুসন্ধান করা প্রায় 3000 ফলাফলের সারণী করা (একটি টেবিলের মূল্যবান ফাংশন সহ বেশ কয়েকটি যোগদানের সাথে), এটি মিলিসেকেন্ডগুলি নিয়েছিল - দুর্দান্ত!
জেকেরাক

142

COUNT ( ) ওভার () পদ্ধতিটি ব্যবহার করে কিছু কার্য সম্পাদনের সমস্যার মুখোমুখি হয়েছি (আমি নিশ্চিত নই যে এটি সার্ভার ছিল কারণ এটি 10 ​​টি রেকর্ড ফিরে আসতে 40 সেকেন্ড সময় নিয়েছিল এবং পরে কোনও সমস্যা নেই)) এই কৌশলটি COUNT ( ) ওভার () ব্যবহার না করে সমস্ত শর্তে কাজ করেছে এবং সম্পূর্ণ করে একই জিনিস:

DECLARE 
    @PageSize INT = 10, 
    @PageNum  INT = 1;

WITH TempResult AS(
    SELECT ID, Name
    FROM Table
), TempCount AS (
    SELECT COUNT(*) AS MaxRows FROM TempResult
)
SELECT *
FROM TempResult, TempCount
ORDER BY TempResult.Name
    OFFSET (@PageNum-1)*@PageSize ROWS
    FETCH NEXT @PageSize ROWS ONLY

32
এটি যদি ভেরিয়েবলের মধ্যে COUNT (*) মান সংরক্ষণ করার সম্ভাবনা থাকে তবে তা সত্যিই দুর্দান্ত। আমি এটি আমার সঞ্চিত প্রক্রিয়াটির একটি OUTPUT প্যারামিটার হিসাবে সেট করতে সক্ষম হব। কোন ধারনা?
কা

4
আলাদা টেবিলে গণনা পাওয়ার কোনও উপায় আছে কি? দেখে মনে হচ্ছে আপনি কেবলমাত্র পূর্ববর্তী SELECT স্টেটমেন্টের জন্য "টেম্পারসাল্ট" ব্যবহার করতে পারেন।
ম্যাঠো 1460

4
কেন এই কাজ এত ভাল করে? প্রথম সিটিইতে, সমস্ত সারি নির্বাচন করা হয়, তারপরে আনতে হবে। আমি অনুমান করতাম যে প্রথম সিটিইতে সমস্ত সারি নির্বাচন করা বিষয়গুলিকে উল্লেখযোগ্যভাবে ধীর করে দেবে। যাই হোক না কেন, এই জন্য ধন্যবাদ!
jbd

4
আমার ক্ষেত্রে এটি COUNT (1) ওভার () এর চেয়ে ধীর হয়ে গেছে .. হতে পারে নির্বাচনের কোনও ফাংশন কারণ।
তিজু জন

4
এটি ছোট ডাটাবেসের জন্য নিখুঁত কাজ করে যখন সারিগুলি মিলিয়ন হয় তবে এটি খুব বেশি সময় নেয়।
কিয়া

1

জেমস মোবার্গের উত্তরের ভিত্তিতে :

এটি আপনার বিকল্প Row_Number()এসকিউএল সার্ভার না থাকলে 2012 এবং আপনি অফসেট ব্যবহার করতে পারবেন না using

DECLARE 
    @PageNumEnd INT = 10, 
    @PageNum  INT = 1;

WITH TempResult AS(
    SELECT ID, NAME
    FROM Tabla
), TempCount AS (
    SELECT COUNT(*) AS MaxRows FROM TempResult
)

select * 
from
(
    SELECT
     ROW_NUMBER() OVER ( ORDER BY PolizaId DESC) AS 'NumeroRenglon', 
     MaxRows, 
     ID,
     Name
    FROM TempResult, TempCount

)resultados
WHERE   NumeroRenglon >= @PageNum
    AND NumeroRenglon <= @PageNumEnd
ORDER BY NumeroRenglon
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.