একটি সীমাবদ্ধ / অফসেট দিয়ে একটি ক্যোয়ারী চালান এবং সারির মোট সংখ্যা পান get


101

পৃষ্ঠাগুলি উদ্দেশ্যে, আমার কাছে একটি ক্লোইস প্রয়োজন LIMITএবং OFFSETক্লজগুলি নিয়ে দরকার। তবে আমার কাছে এমন সারিগুলির একটি সংখ্যাও প্রয়োজন যা সেই ক্লোয়ারীর দ্বারা শর্তগুলি LIMITএবং OFFSETধারাগুলি ব্যতীত ফিরে আসবে ।

আমি চালাতে চাই:

SELECT * FROM table WHERE /* whatever */ ORDER BY col1 LIMIT ? OFFSET ?

এবং:

SELECT COUNT(*) FROM table WHERE /* whatever */

একই সাথে এটি করার কোনও উপায় আছে, বিশেষত এমন কোনও উপায় যা পোস্টগ্র্রেসকে এটিকে অনুকূল করে তুলতে দেয়, যাতে এটি পৃথকভাবে উভয়ই চালনার চেয়ে দ্রুত হয়?


উত্তর:


178

হ্যাঁ. একটি সাধারণ উইন্ডো ফাংশন সহ:

SELECT *, count(*) OVER() AS full_count
FROM   tbl
WHERE  /* whatever */
ORDER  BY col1
OFFSET ?
LIMIT  ?

মোট সচেতনতা ব্যতীত ব্যয়টি যথেষ্ট পরিমাণে বেশি হলেও সচরাচর দুটি পৃথক প্রশ্নের চেয়ে সস্তা aware পোস্টগ্রিসকে প্রকৃতপক্ষে সমস্ত সারি গণনা করতে হবে , যা মোট যোগ্যতার সারিগুলির মোট সংখ্যার উপর নির্ভর করে ব্যয় আরোপ করে। বিশদ:

যাইহোক , দানি যেভাবে উল্লেখ করেছেন , OFFSETবেস ক্যোয়ারী থেকে কমপক্ষে সারিগুলির সংখ্যার চেয়ে বড় হয়ে গেলে কোনও সারি ফিরে আসে না। সুতরাং আমরাও পাই না full_count

যদি তা গ্রহণযোগ্য না হয় তবে সর্বদা সম্পূর্ণ গণনা ফেরত দেওয়ার সম্ভাব্য কাজটি সিটিই এবং একটি সহ OUTER JOIN:

WITH cte AS (
   SELECT *
   FROM   tbl
   WHERE  /* whatever */
   )
SELECT *
FROM  (
   TABLE  cte
   ORDER  BY col1
   LIMIT  ?
   OFFSET ?
   ) sub
RIGHT  JOIN (SELECT count(*) FROM cte) c(full_count) ON true;

খুব বড় full_countহলে সংযুক্তিগুলির সাথে আপনি এক সারিতে NULL মান পাবেন OFFSET। অন্যথায়, এটি প্রথম ক্যোয়ারের মতো প্রতিটি সারিতে যুক্ত হয়।

সমস্ত NULL মান সহ একটি সারি যদি সম্ভব বৈধ ফলাফল হয় তবে আপনাকে offset >= full_countখালি সারির উত্স ছিন্ন করতে পরীক্ষা করতে হবে।

এটি এখনও একবারে বেস ক্যোয়ারী চালায়। তবে এটি ক্যোয়ারীতে আরও ওভারহেড যুক্ত করে এবং কেবলমাত্র পেমেন্ট দেয় যদি এটি গণনার জন্য বেস কোয়েরি পুনরাবৃত্তি করার চেয়ে কম হয়।

যদি চূড়ান্ত বাছাই অর্ডারকে সমর্থন করে সূচকগুলি উপলভ্য থাকে তবে ORDER BYএটি সিটিইতে অন্তর্ভুক্ত করার জন্য অর্থ দিতে পারে (অতিরিক্তভাবে)।


4
দুটি সীমাবদ্ধতা এবং শর্তাবলী অনুসারে, আমাদের কাছে ফেরত পাঠানোর সারি রয়েছে, তবে প্রদত্ত অফসেটের সাথে এটি কোনও ফল দেয় না। এই পরিস্থিতিতে, আমরা কীভাবে সারি গণনা করতে সক্ষম হব?
দানি ম্যাথিউ

খুব সুন্দর, ধন্যবাদ, আপনি যখন পৃষ্ঠাগুলি, ডেটাবেবল ব্যবহার করেন তখন দুর্দান্ত কাজ করে, কেবল এটি আপনার স্কয়ারের শুরুতে যুক্ত করুন এবং এটি ব্যবহার করুন, মোট গণনার জন্য একটি অতিরিক্ত ক্যোয়ারী সংরক্ষণ করুন।
আহমেদ সানি 8

আপনি কি এই বিষয়ে বিস্তারিত বলতে পারেন যদি একটি ইনপুট প্যারামিটারের মাধ্যমে প্রশ্নটিতে গণনাটি গতিশীলভাবে সক্ষম করা যায়? আমার অনুরূপ প্রয়োজনীয়তা রয়েছে তবে ব্যবহারকারী সিদ্ধান্ত নেন যে তিনি ইনলাইন গণনা চান কিনা।
জুলাইগলন

4
@ জুলাইলেগন: দয়া করে সংজ্ঞায়িত বিশদ দিয়ে একটি নতুন প্রশ্ন শুরু করুন। আপনি প্রাসঙ্গিকতার জন্য সর্বদা এটির সাথে লিঙ্ক করতে পারেন এবং যদি আপনি চান তবে ফিরে লিঙ্ক করতে এখানে একটি মন্তব্য যুক্ত করুন (এবং আমার দৃষ্টি আকর্ষণ করুন)।
এরউইন ব্র্যান্ডসটেটার

4
@ জাস্টিনএল: যোগ করা ওভারহেড কেবল তুলনামূলকভাবে সস্তা বেস প্রশ্নের জন্য গুরুত্বপূর্ণ হওয়া উচিত। এছাড়াও, পোস্টগ্রিস 12 সিটিইর কার্যকারিতা একাধিক উপায়ে উন্নত করেছে। (যদিও এই সিটিই MATERIALIZEDডিফল্টরূপে এখনও দু'বার উল্লেখ করা হয়েছে))
এরউইন ব্র্যান্ডসেটেটার

0

সম্পাদনা করুন: অসম্পূর্ণ ছকটি পুনরুদ্ধার করার সময় এই উত্তরটি বৈধ। এটি কারওর পক্ষে সহায়তা করতে পারলে আমি এটিকে ছেড়ে দেব তবে এটি প্রাথমিক প্রশ্নের সঠিক উত্তর দিতে পারে না।

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

SELECT *
FROM (
    SELECT *
    FROM tbl
    WHERE /* something */
    ORDER BY /* something */
    OFFSET ?
    LIMIT ?
    ) data
RIGHT JOIN (SELECT reltuples FROM pg_class WHERE relname = 'tbl') pg_count(total_count) ON true;

আমি বাস্তবে নিশ্চিত নই যে বাহ্যিককরণের কোনও সুবিধা RIGHT JOINআছে বা এটি স্ট্যান্ডার্ড ক্যোয়ারির মতো রয়েছে। এটি কিছু পরীক্ষার প্রাপ্য হবে।

SELECT t.*, pgc.reltuples AS total_count
FROM tbl as t
RIGHT JOIN pg_class pgc ON pgc.relname = 'tbl'
WHERE /* something */
ORDER BY /* something */
OFFSET ?
LIMIT ?

4
দ্রুত গণনা অনুমান সম্পর্কে: স্ট্যাকওভারফ্লো.com / a / 7945274 / 939860 আপনি বলেছেন: পুরো টেবিলটি পুনরুদ্ধার করার সময় বৈধ - যা WHEREআপনার প্রশ্নগুলির ধারা দ্বারা বিপরীত । দ্বিতীয় ক্যোয়ারী এটি যৌক্তিকভাবে ভুল ( ডিবিতে প্রতিটি টেবিলের জন্য একটি সারি পুনরুদ্ধার করে ) - এবং ঠিক করা হলে আরও ব্যয়বহুল।
এরউইন ব্র্যান্ডসেটেটার

0

যদিও এরউইন Brandstetter এর উত্তর একটি যাদুমন্ত্র মত কাজ করে, এটা সারির মোট গণনা ফেরৎ যে সারিতে নিম্নলিখিত মত:

col1 - col2 - col3 - total
--------------------------
aaaa - aaaa - aaaa - count
bbbb - bbbb - bbbb - count
cccc - cccc - cccc - count

আপনি নীচের মত মোট একবার গণনা ফেরত এমন একটি পদ্ধতির ব্যবহার বিবেচনা করতে চাইতে পারেন :

total - rows
------------
count - [{col1: 'aaaa'},{col2: 'aaaa'},{col3: 'aaaa'}
         {col1: 'bbbb'},{col2: 'bbbb'},{col3: 'bbbb'}
         {col1: 'cccc'},{col2: 'cccc'},{col3: 'cccc'}]

এসকিউএল কোয়েরি:

SELECT 
    (SELECT COUNT(*) FROM table) as count, 
    (SELECT json_agg(t.*) FROM (
        SELECT * FROM table
        WHERE /* whatever */
        ORDER BY col1
        OFFSET ?
        LIMIT ?
    ) AS t) AS rows 

-6

কেবল পুনঃপ্রাপ্ত ফলাফলের সারিগুলির মোট সংখ্যা পাওয়ার জন্য দু'বার একই জিজ্ঞাসা কল করা তার খারাপ অনুশীলন। এটি কার্যকর করার সময় নেবে এবং সার্ভারের সংস্থান নষ্ট করবে।

আরও ভাল, আপনি SQL_CALC_FOUND_ROWSক্যোয়ারিতে ব্যবহার করতে পারেন যা মাইএসকিউএলকে সীমা সন্ধানের ফলাফলের সাথে সারি গণনার মোট সংখ্যা আনতে বলবে।

উদাহরণ সেট হিসাবে সেট করুন:

SELECT SQL_CALC_FOUND_ROWS employeeName, phoneNumber FROM employee WHERE employeeName LIKE 'a%' LIMIT 10;

SELECT FOUND_ROWS();

উপরের কোয়েরিতে, কেবলমাত্র SQL_CALC_FOUND_ROWSপ্রয়োজনীয় প্রয়োজনীয় ক্যোয়ারীতে অপশন যুক্ত করুন এবং দ্বিতীয় লাইনটি কার্যকর করুন অর্থাত্ SELECT FOUND_ROWS()বিবৃতিতে ফিরে আসা ফলাফলের সারিগুলির সংখ্যা প্রদান করে।


4
সমাধানটির জন্য মাইএসকিএল নয় পোস্টগ্রিজ প্রয়োজন।
মাফিনমান

@ মাফিনম্যান, আপনি এটি মাইএসকিএল-তে ব্যবহার করতে পারেন। এমওয়াইএসকিউএল ৪.০ থেকে, এটি ক্যোয়ারিতে SQL_CALC_FOUND_ROWS বিকল্পটি ব্যবহৃত হচ্ছে। তবে এমওয়াইএসকিউএল ৮.০ থেকে এটি বাতিল করা হয়েছে।
মোহাম্মদ রশিদ

প্রাসঙ্গিক না. এই প্রশ্নের উত্তর বহু বছর আগে দেওয়া হয়েছিল। আপনি যদি অবদান রাখতে চান তবে একই বিষয় নিয়ে একটি নতুন প্রশ্ন পোস্ট করুন তবে মাইএসকিউএল-এর সাথে নির্দিষ্ট specific
মাফিনমন

সর্বদা প্রাসঙ্গিক থাকুন
আলী হুসেন

-15

না

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

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