কোনটি দ্রুততম? নির্বাচন করুন এসকিউএল_সিএলসি_ফাউND_ROWS থেকে `টেবিল`, বা নির্বাচন করুন COUNT (*)


176

সাধারণত যখন পেজিংয়ে ব্যবহৃত হয় এসকিউএল কোয়েরি দ্বারা সারিগুলির সংখ্যাটি সীমাবদ্ধ করা হয়, মোট রেকর্ডের সংখ্যা নির্ধারণ করার জন্য দুটি পদ্ধতি রয়েছে:

পদ্ধতি 1

মূলটিতে SQL_CALC_FOUND_ROWSবিকল্পটি অন্তর্ভুক্ত করুন SELECTএবং তারপরে চালিয়ে মোট সারির সংখ্যা পান SELECT FOUND_ROWS():

SELECT SQL_CALC_FOUND_ROWS * FROM table WHERE id > 100 LIMIT 10;
SELECT FOUND_ROWS();  

পদ্ধতি 2

কোয়েরিটি সাধারণত চালান এবং তারপরে চালিয়ে মোট সারির সংখ্যা পান SELECT COUNT(*)

SELECT * FROM table WHERE id > 100 LIMIT 10;
SELECT COUNT(*) FROM table WHERE id > 100;  

কোন পদ্ধতিটি সেরা / দ্রুততম?

উত্তর:


120

এটা নির্ভর করে. এই বিষয়ে মাইএসকিউএল পারফরম্যান্স ব্লগ পোস্টটি দেখুন: http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

কেবলমাত্র একটি দ্রুত সংক্ষিপ্তসার: পিটার বলেছেন যে এটি আপনার সূচি এবং অন্যান্য বিষয়গুলির উপর নির্ভর করে। পোস্টটিতে বেশিরভাগ মন্তব্যে মনে হয় যে এসকিউএল_সিএলসি_এফইউ END_ROWS প্রায় সবসময় ধীর - কখনও কখনও 10 এক্স পর্যন্ত ধীর - দুটি ক্যোয়ারী চালানোর চেয়ে কম।


27
আমি এটি নিশ্চিত করতে পারি - আমি মাত্র একটি 168,000 সারি ডাটাবেসে 4 যোগ দিয়ে একটি ক্যোয়ারী আপডেট করেছি। SQL_CALC_FOUND_ROWS20 সেকেন্ডেরও বেশি সময় নিয়ে প্রথম 100 টি সারি নির্বাচন করা ; একটি পৃথক COUNT(*)ক্যোয়ারী ব্যবহার করতে 5 সেকেন্ডেরও বেশি সময় লেগেছিল (উভয় গণনা + ফলাফলের প্রশ্নের জন্য)।
স্যাম ডুফেল

9
খুব আকর্ষণীয় অনুসন্ধান। যেহেতু মাইএসকিউএল এর ডকুমেন্টেশনগুলি স্পষ্টভাবে পরামর্শ দেয় যে SQL_CALC_FOUND_ROWSদ্রুততর হবে, তাই আমি অবাক হয়েছি কোন পরিস্থিতিতে এটি (যদি কোনও হয়) আসলে এটি আরও দ্রুত!
এসভিডজেন

12
পুরানো বিষয়, তবে যারা এখনও আকর্ষণীয়! আইএনএনওডিবিতে আমার চেকটি 10 ​​টি চেক থেকে সবেমাত্র শেষ হয়েছে আমি বলতে পারি যে এটি 9 (2 ক্যুরি) এর বিপরীতে 26 (2 কোয়েরি) এসকিউএল_সিএলসি_ফাউND_ROWS টিবিএলএ নির্বাচন করুন। *, tblB.id AS 'b_id', tblB.city AS 'b_city', tblC.id AS 'c_id', tblC.type হিসাবে 'c_type', tblD.id হিসাবে 'd_id', tblD.extype হিসাবে 'd_extype', tblY.id হিসাবে 'y_id' থেকে tblY.ydt আঃ y_ydt tblA, tblB, tblC, tblD, tblY কোথায় tblA.b = tblC.id এবং tblA.c = tblB.id এবং tblA.d = tblD.id এবং tblA.y = tblY.id
আল পো

4
আমি সবেমাত্র এই পরীক্ষাটি চালিয়েছি এবং এসকিউএলসি_সিএলসি_এফউND_ROWS দুটি প্রশ্নের চেয়ে অনেক দ্রুত ছিল W এখন আমার মূল টেবিলটি মাত্র 65 কে এবং কয়েক শ কয়েক জনের সাথে যোগ দেয়, তবে মূল ক্যোয়ারিতে SQLC_CALC_FOUND_ROWS এর সাথে বা ছাড়াই 0.18 সেকেন্ড সময় লাগে তবে আমি যখন COUNT এর সাথে দ্বিতীয় জিজ্ঞাসা চালিয়েছিলাম তখন idএটি 0.25 একা লেগেছিল।
transilvlad

1
সম্ভাব্য পারফরম্যান্সের সমস্যাগুলি ছাড়াও, FOUND_ROWS()এটি মাইএসকিউএল 8.0.17 এ অবহেলা করা হয়েছে তা বিবেচনা করুন । @ মধুর-ভাইয়ার উত্তরও দেখুন।
arueckauer

19

"সেরা" পদ্ধতির চয়ন করার সময়, গতির চেয়ে আরও গুরুত্বপূর্ণ বিবেচনাটি আপনার কোডের রক্ষণাবেক্ষণ এবং সঠিকতা হতে পারে। যদি তা হয় তবে এসকিউএল_সিএলসি_এফআউইউআরআউআরআউআউউএস পছন্দনীয় কারণ আপনার কেবলমাত্র একটি একক ক্যোয়ারী বজায় রাখতে হবে। একটি একক ক্যোয়ারী ব্যবহার করা সম্পূর্ণরূপে মূল এবং গণনা প্রশ্নের মধ্যে একটি সূক্ষ্ম পার্থক্যের সম্ভাবনাকে বাদ দেয়, যার ফলে কোনও ত্রুটিযুক্ত COUNT হতে পারে।


11
এটি আপনার সেটআপের উপর নির্ভর করে। আপনি যদি কোনও ধরণের ওআরএম বা কোয়েরি বিল্ডার ব্যবহার করেন তবে উভয় প্রশ্নের জন্য মাপদণ্ড, গণনার জন্য নির্বাচিত ক্ষেত্রগুলি অদলবদল করে এবং সীমাটি বাদ দিন সেখানে একই ব্যবহার করা খুব সহজ। আপনার দু'বার মানদণ্ডটি কখনই লেখা উচিত নয়।
এমপেন

আমি উল্লেখ করব যে আমি বরং দুটি সাধারণ মোটামুটি স্ট্যান্ডার্ড ব্যবহার করে কোড বজায় রাখতে চাইছি, যার মালিকানাধীন মাইএসকিউএল বৈশিষ্ট্যটি ব্যবহার করা হয় তার চেয়ে এসকিউএল কোয়েরিগুলি বোঝা সহজ - যা মাইএসকিউএল সংস্করণগুলিতে লক্ষ্যণীয়।
থোমাসরুটটার

15

মাইএসকিউএল SQL_CALC_FOUND_ROWS8.0.17 সংস্করণ সহ কার্যকারিতা হ্রাস করা শুরু করেছে ।

সুতরাং, এটা করা হয় সবসময় পছন্দের সঙ্গে আপনার প্রশ্নের নির্বাহ বিবেচনা LIMITকরুন, এবং তারপর সঙ্গে তার দ্বিতীয় ক্যোয়ারী COUNT(*)ছাড়া LIMITনির্ধারণ করতে অতিরিক্ত সারি আছে কিনা।

ডক্স থেকে :

SQL_CALC_FOUND_ROWS ক্যোয়ারী সংশোধক এবং তার সাথে থাকা FOUND_ROWS () ফাংশনটি মাইএসকিউএল 8.0.17 হিসাবে অবহিত এবং ভবিষ্যতে মাইএসকিউএল সংস্করণে সরানো হবে।

COUNT (*) নির্দিষ্ট অপ্টিমাইজেশানের সাপেক্ষে। SQL_CALC_FOUND_ROWS কিছু অপ্টিমাইজেশন অক্ষম করে to

পরিবর্তে এই প্রশ্নগুলি ব্যবহার করুন:

SELECT * FROM tbl_name WHERE id > 100 LIMIT 10;
SELECT COUNT(*) WHERE id > 100;

এছাড়াও, মাইএসকিউএল ডাব্লুএল # 12615SQL_CALC_FOUND_ROWS তে বর্ণিত হিসাবে আরও বেশি সমস্যা থাকতে দেখা গেছে :

SQL_CALC_FOUND_ROWS এর বেশ কয়েকটি সমস্যা রয়েছে। প্রথমত, এটি ধীর। প্রায়শই, সীমাবদ্ধতার সাথে ক্যোরি চালানো সস্তা হবে এবং তারপরে একই ক্যোয়ারির জন্য আলাদা আলাদা নির্বাচন করুন ( ), যেহেতু COUNT ( ) সম্পূর্ণ ফলাফলের সেটটি অনুসন্ধান করার জন্য করা যায় না এমন অপ্টিমাইজেশন ব্যবহার করতে পারে (যেমন ফাইলসোর্ট COUNT (*) এর জন্য এড়ানো যেতে পারে, তবে CALC_FOUND_ROWS এর সাথে, সঠিক ফলাফলের গ্যারান্টি দিতে আমাদের কিছু ফাইলপোর্ট অপ্টিমাইজেশান অক্ষম করতে হবে)

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

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


কীভাবে এই দুটি নির্বাচনকে পারমাণবিক অপারেশন হিসাবে সম্পাদন করবেন? কেউ যদি নির্বাচিত COUNT (*) ক্যোয়ারির আগে একটি সারি প্রবেশ করান তবে কী হবে? ধন্যবাদ।
ডোম

@ ডোম যদি আপনার মাইএসকিউএল 8 + থাকে তবে উইন্ডো ফাংশন ব্যবহার করে আপনি উভয় ক্যোয়ারিকে একক ক্যোয়ারিতে চালাতে পারবেন; তবে সূচকগুলি সঠিকভাবে ব্যবহার করা হবে না বলে এটি সর্বোত্তম সমাধান হবে না। আরেকটি বিকল্প এই দুটি প্রশ্নের ঘিরে হয় LOCK TABLES <tablename>এবং UNLOCK TABLES। তৃতীয় বিকল্প এবং (সেরা আইএমএইচও) হ'ল পৃষ্ঠাগুলি পুনর্বিবেচনা করা। দয়া করে পড়ুন: mariadb.com/kb/en/library/pagination-optimization
মধুর ভাইয়া

14

নিম্নলিখিত নিবন্ধ অনুসারে: https://www.percona.com/blog/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/

আপনি একটি থাকে তাহলে এর INDEX (যদি আইডি আপনার ক্ষেত্রে সূচীবদ্ধ করা হয়) আপনার যেখানে দফা উপর, তারপর এটি ভাল ব্যবহার করতে নয় SQL_CALC_FOUND_ROWS পরিবর্তে 2 প্রশ্নের ব্যবহার করেন, কিন্তু আপনি যা আপনি আপনার যেখানে দফা রাখা উপর একটি সূচক না থাকে তাহলে (আপনার ক্ষেত্রে আইডি) তারপরে SQL_CALC_FOUND_ROWS ব্যবহার করা আরও দক্ষ।


8

আইএমএইচও, 2 টি প্রশ্নের কারণ

SELECT * FROM count_test WHERE b = 666 ORDER BY c LIMIT 5;
SELECT count(*) FROM count_test WHERE b = 666;

SQL_CALC_FOUND_ROWS ব্যবহার করার চেয়ে দ্রুত

SELECT SQL_CALC_FOUND_ROWS * FROM count_test WHERE b = 555 ORDER BY c LIMIT 5;

একটি বিশেষ কেস হিসাবে দেখা যেতে হবে।

এটি অর্ডার + লিমিটেডের সমতুল্য অন্তর্নিহিত একের চূড়ান্ততার তুলনায় WHERE ধারাটির নির্বাচনের উপর নির্ভর করে।

যেমন অরভিডস মন্তব্যে জানিয়েছিল ( http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/#comment-1174394 ), ব্যবহার করেছে বা না, একটি অস্থায়ী টেবিল, এসসিএফআর দ্রুততর হবে কিনা তা জানার জন্য একটি ভাল বেস হওয়া উচিত।

তবে, আমি যেমন যুক্ত করেছি ( http://www.mysqlperformanceblog.com/2007/08/28/to-sql_calc_found_rows-or-not-to-sql_calc_found_rows/#comment-8166482 ) ফলাফল সত্যিই কেসের উপর নির্ভর করে। কোনও নির্দিষ্ট প্যাগিনেটরের জন্য, আপনি এই সিদ্ধান্তে পৌঁছতে পারেন যে "3 প্রথম পৃষ্ঠার জন্য, 2 টি কোয়েরি ব্যবহার করুন; নিম্নলিখিত পৃষ্ঠাগুলির জন্য, একটি এসসিএফআর ব্যবহার করুন ”!


6

কিছু অপ্রয়োজনীয় এসকিউএল অপসারণ এবং তার COUNT(*)চেয়ে দ্রুত হবে SQL_CALC_FOUND_ROWS। উদাহরণ:

SELECT Person.Id, Person.Name, Job.Description, Card.Number
FROM Person
JOIN Job ON Job.Id = Person.Job_Id
LEFT JOIN Card ON Card.Person_Id = Person.Id
WHERE Job.Name = 'WEB Developer'
ORDER BY Person.Name

তারপরে অপ্রয়োজনীয় অংশ ব্যতীত গণনা করুন:

SELECT COUNT(*)
FROM Person
JOIN Job ON Job.Id = Person.Job_Id
WHERE Job.Name = 'WEB Developer'

3

আপনার জন্য মাপদণ্ডের জন্য অন্যান্য বিকল্প রয়েছে:

১) উইন্ডো ফাংশনটি আসল আকারটি সরাসরি ফিরে আসবে (মারিয়াডিবিতে পরীক্ষিত):

SELECT 
  `mytable`.*,
  COUNT(*) OVER() AS `total_count`
FROM `mytable`
ORDER BY `mycol`
LIMIT 10, 20

2.) বাক্সের বাইরে চিন্তা, সময় ব্যবহারকারীদের অধিকাংশই জানে প্রয়োজন হবে না EXACT টেবিলের আকার একটি আনুমানিক প্রায়ই ভাল যথেষ্ট।

SELECT `TABLE_ROWS` AS `rows_approx`
FROM `INFORMATION_SCHEMA`.`TABLES`
WHERE `TABLE_SCHEMA` = DATABASE()
  AND `TABLE_TYPE` = "BASE TABLE"
  AND `TABLE_NAME` = ?
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.