সুতরাং আপনি OrderField
প্রতি গ্রুপে সর্বাধিক সারি পেতে চান ? আমি এটি এইভাবে করব:
SELECT t1.*
FROM `Table` AS t1
LEFT OUTER JOIN `Table` AS t2
ON t1.GroupId = t2.GroupId AND t1.OrderField < t2.OrderField
WHERE t2.GroupId IS NULL
ORDER BY t1.OrderField; // not needed! (note by Tomas)
( টমাস দ্বারা সম্পাদনা করুন: যদি একই গ্রুপের মধ্যে একই অর্ডারফিল্ডের সাথে আরও রেকর্ড থাকে এবং আপনার ঠিক এর মধ্যে একটির প্রয়োজন হয় তবে আপনি শর্তটি প্রসারিত করতে চাইতে পারেন:
SELECT t1.*
FROM `Table` AS t1
LEFT OUTER JOIN `Table` AS t2
ON t1.GroupId = t2.GroupId
AND (t1.OrderField < t2.OrderField
OR (t1.OrderField = t2.OrderField AND t1.Id < t2.Id))
WHERE t2.GroupId IS NULL
সম্পাদনার সমাপ্তি।)
অন্য কথায়, সেই সারিটি ফিরিয়ে দিন t1
যার জন্য অন্য কোনও সারি t2
একই GroupId
এবং বৃহত্তর সাথে উপস্থিত নেই OrderField
। কখন t2.*
NULL হয়, এর অর্থ বাম বাহিরের জোড় এর সাথে তেমন কোনও মিল খুঁজে পাওয়া যায় নি, এবং তাই গ্রুপে t1
সর্বাধিক মান রয়েছে OrderField
।
কোনও পদ নেই, কোন উপশক্তি নেই। এটি দ্রুত চালানো উচিত এবং আপনার কোনও যৌগ সূচক চালু থাকলে "ইনডেক্স" ব্যবহার করে টি 2-এ অ্যাক্সেসের অনুকূলিতকরণ করা উচিত (GroupId, OrderField)
।
পারফরম্যান্স সম্পর্কে, প্রতিটি গ্রুপের সর্বশেষ রেকর্ড পুনরুদ্ধার করার জন্য আমার উত্তর দেখুন । স্ট্যাক ওভারফ্লো ডেটা ডাম্প ব্যবহার করে আমি সাব-কোয়েরি পদ্ধতি এবং যোগদানের পদ্ধতিটি চেষ্টা করেছি। পার্থক্যটি লক্ষণীয়: যোগদানের পদ্ধতিটি আমার পরীক্ষায় 278 গুণ বেশি দ্রুত গতিতে চলেছিল।
সেরা ফলাফল পাওয়ার জন্য আপনার সঠিক সূচীটি থাকা গুরুত্বপূর্ণ!
@ র্যাঙ্ক ভেরিয়েবলটি ব্যবহার করে আপনার পদ্ধতি সম্পর্কে, আপনি যেমনটি লিখেছেন তেমন কার্যকর হবে না, কারণ প্রশ্নের প্রথম টেবিলটি প্রক্রিয়া করার পরে @ র্যাঙ্কের মানগুলি শূন্যে পুনরায় সেট হবে না। আমি আপনাকে একটি উদাহরণ দেখাব।
আমি কিছু ডামি ডেটা sertedোকালাম, একটি অতিরিক্ত ক্ষেত্রের সাথে শূন্য যা আমরা জানি যে সারিটি প্রতি গ্রুপে সর্বাধিক:
select * from `Table`;
+
| GroupId | OrderField | foo |
+
| 10 | 10 | NULL |
| 10 | 20 | NULL |
| 10 | 30 | foo |
| 20 | 40 | NULL |
| 20 | 50 | NULL |
| 20 | 60 | foo |
+
আমরা দেখাতে পারি যে র্যাঙ্কটি প্রথম গ্রুপের জন্য তিনটি এবং দ্বিতীয় গ্রুপের জন্য ছয়টিতে বৃদ্ধি পেয়েছে এবং অভ্যন্তরীণ কোয়েরিগুলি এগুলি সঠিকভাবে প্রদান করে:
select GroupId, max(Rank) AS MaxRank
from (
select GroupId, @Rank := @Rank + 1 AS Rank
from `Table`
order by OrderField) as t
group by GroupId
+
| GroupId | MaxRank |
+
| 10 | 3 |
| 20 | 6 |
+
সমস্ত সারিগুলির কার্টেসিয়ান পণ্য জোর করতে, এখন কোনও যোগদানের শর্ত ছাড়াই ক্যোয়ারি চালান, এবং আমরা সমস্ত কলামও আনি:
select s.*, t.*
from (select GroupId, max(Rank) AS MaxRank
from (select GroupId, @Rank := @Rank + 1 AS Rank
from `Table`
order by OrderField
) as t
group by GroupId) as t
join (
select *, @Rank := @Rank + 1 AS Rank
from `Table`
order by OrderField
) as s
order by OrderField;
+
| GroupId | MaxRank | GroupId | OrderField | foo | Rank |
+
| 10 | 3 | 10 | 10 | NULL | 7 |
| 20 | 6 | 10 | 10 | NULL | 7 |
| 10 | 3 | 10 | 20 | NULL | 8 |
| 20 | 6 | 10 | 20 | NULL | 8 |
| 20 | 6 | 10 | 30 | foo | 9 |
| 10 | 3 | 10 | 30 | foo | 9 |
| 10 | 3 | 20 | 40 | NULL | 10 |
| 20 | 6 | 20 | 40 | NULL | 10 |
| 10 | 3 | 20 | 50 | NULL | 11 |
| 20 | 6 | 20 | 50 | NULL | 11 |
| 20 | 6 | 20 | 60 | foo | 12 |
| 10 | 3 | 20 | 60 | foo | 12 |
+
আমরা উপরের দিক থেকে দেখতে পাচ্ছি যে প্রতি গ্রুপে সর্বাধিক র্যাঙ্কটি সঠিক, তবে তারপরে @ র্যাঙ্কটি দ্বিতীয় উত্পন্ন টেবিলটি প্রক্রিয়াকরণ করার সাথে সাথে 7 থেকে উচ্চতর বৃদ্ধি পেতে থাকবে। সুতরাং দ্বিতীয় উত্পন্ন টেবিল থেকে র্যাঙ্কগুলি কখনই প্রথম উত্পন্ন টেবিল থেকে র্যাঙ্কের সাথে কখনই ওভারল্যাপ করবে না।
দুটি টেবিল প্রক্রিয়াকরণের মধ্যে @ র্যাঙ্ককে শূন্যে পুনরায় সেট করতে জোর করতে আপনাকে আর একটি উত্সযুক্ত টেবিল যুক্ত করতে হবে (এবং আশা করি অপ্টিমাইজারটি যে সারণীর মূল্যায়ন করে তাতে ক্রমটি পরিবর্তন হয় না, বা তা রোধ করতে স্ট্রাইটাইএটT_ জয়ন ব্যবহার করুন):
select s.*
from (select GroupId, max(Rank) AS MaxRank
from (select GroupId, @Rank := @Rank + 1 AS Rank
from `Table`
order by OrderField
) as t
group by GroupId) as t
join (select @Rank := 0) r
join (
select *, @Rank := @Rank + 1 AS Rank
from `Table`
order by OrderField
) as s
on t.GroupId = s.GroupId and t.MaxRank = s.Rank
order by OrderField;
+
| GroupId | OrderField | foo | Rank |
+
| 10 | 30 | foo | 3 |
| 20 | 60 | foo | 6 |
+
তবে এই ক্যোয়ারীর অপটিমাইজেশনটি ভয়াবহ। এটি কোনও সূচী ব্যবহার করতে পারে না, এটি দুটি অস্থায়ী টেবিল তৈরি করে, এগুলিকে কঠোরভাবে বাছাই করে এবং এমনকি জয়েন বাফার ব্যবহার করে কারণ টেম্প টেবিলগুলিতে যোগদান করার সময় এটি কোনও সূচক ব্যবহার করতে পারে না। এটি উদাহরণ থেকে আউটপুট EXPLAIN
:
+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+
| 1 | PRIMARY | <derived4> | system | NULL | NULL | NULL | NULL | 1 | Using temporary; Using filesort |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 2 | |
| 1 | PRIMARY | <derived5> | ALL | NULL | NULL | NULL | NULL | 6 | Using where; Using join buffer |
| 5 | DERIVED | Table | ALL | NULL | NULL | NULL | NULL | 6 | Using filesort |
| 4 | DERIVED | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |
| 2 | DERIVED | <derived3> | ALL | NULL | NULL | NULL | NULL | 6 | Using temporary; Using filesort |
| 3 | DERIVED | Table | ALL | NULL | NULL | NULL | NULL | 6 | Using filesort |
+
যদিও আমার সমাধানটি বাম বাহিরের জোড় ব্যবহার করে আরও ভালতর করে। এটি কোনও টেম্প টেবিল এবং এমনকী প্রতিবেদনগুলি ব্যবহার করে "Using index"
যার অর্থ এটি কোনও ডেটা স্পর্শ না করে কেবল সূচক ব্যবহার করে জোড়টিকে সমাধান করতে পারে।
+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+
| 1 | SIMPLE | t1 | ALL | NULL | NULL | NULL | NULL | 6 | Using filesort |
| 1 | SIMPLE | t2 | ref | GroupId | GroupId | 5 | test.t1.GroupId | 1 | Using where; Using index |
+
আপনি সম্ভবত তাদের ব্লগে দাবী করা লোকেরা পড়বেন যে "এসকিউএলকে ধীরে ধীরে যোগ দেয়", তবে এটি আজেবাজে কথা। খারাপ অপ্টিমাইজেশন এসকিউএলকে ধীর করে তোলে।