तो क्या आप प्रति समूह उच्चतम 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)
(संपादित करें: मैं इसे इस तरह से करना चाहते हैं, तो एक ही समूह के भीतर एक ही OrderField के साथ और अधिक रिकॉर्ड कर रहे हैं और आप उनमें से ठीक एक की जरूरत है, आप शर्त का विस्तार करने के लिए कर सकते हैं :
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
के साथ मौजूद है और अधिक से अधिकलौट आते हैं।। जब t2.*
पूर्ण है, तो इसका मतलब है कि बाएं बाहरी जुड़ने में ऐसा कोई मिलान नहीं मिला है, और इसलिए t1
समूह में OrderField
का सबसे बड़ा मूल्य है।
कोई रैंक नहीं, कोई सबक्वायरी नहीं। यदि आपके पास (GroupId, OrderField)
पर कंपाउंड इंडेक्स है तो इसे "इंडेक्स का उपयोग करना" के साथ टी 2 तक पहुंच को तेज और अनुकूलित करना चाहिए।
प्रदर्शन के संबंध में, मेरा उत्तर Retrieving the last record in each group पर देखें। मैंने स्टैक ओवरफ़्लो डेटा डंप का उपयोग करके एक सबक्वायरी विधि और जॉइन विधि की कोशिश की। अंतर उल्लेखनीय है: मेरे परीक्षण में शामिल विधि 278 गुना तेजी से बढ़ी।
यह महत्वपूर्ण है कि आपके पास सर्वोत्तम परिणाम प्राप्त करने के लिए सही अनुक्रमणिका हो!
@Rank चर का उपयोग करके आपकी विधि के संबंध में, यह काम नहीं करेगा जैसा आपने लिखा है, क्योंकि क्वेरी के पहले पंक्ति को संसाधित करने के बाद @Rank के मान शून्य पर रीसेट नहीं होंगे। मैं आपको एक उदाहरण दिखाऊंगा।
मैं कुछ डमी डेटा डाला, एक अतिरिक्त क्षेत्र उस पंक्ति हम जानते हैं कि समूह में सबसे बड़ी है पर छोड़कर रिक्त है साथ:
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
-- on t.GroupId = s.GroupId and t.MaxRank = s.Rank
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 और उससे अधिक तक संसाधित करता है। तो दूसरी व्युत्पन्न तालिका से रैंक पहले व्युत्पन्न तालिका से रैंक के साथ कभी भी ओवरलैप नहीं होंगे।
आपको दो तालिकाओं को प्रोसेस करने के बीच शून्य पर रीसेट करने के लिए @ रैंक को मजबूर करने के लिए एक और व्युत्पन्न तालिका जोड़नी होगी (और उम्मीद है कि ऑप्टिमाइज़र उस क्रम को नहीं बदलता है जिसमें यह तालिका का मूल्यांकन करता है, या फिर STRAIGHT_JOIN का उपयोग रोकने के लिए वह):
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 -- RESET @Rank TO ZERO HERE
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 |
+----+-------------+-------+------+---------------+---------+---------+-----------------+------+--------------------------+
आप शायद अपने ब्लॉग पर दावा करने वाले लोगों को पढ़ लेंगे कि "एसक्यूएल धीमा कर देता है," लेकिन यह बकवास है। खराब अनुकूलन एसक्यूएल धीमा बनाता है।
यहां अधिक उन्नत प्रश्न http://stackoverflow.com/questions/9841093/how-to-writegreatest-n-per-group-type-query-but-with-additional-conditions/9845109#9845109 – TMS