Dapatkan rekod terakhir dalam setiap kumpulan - MySQL
P粉464088437
2023-08-24 15:06:23
<p>Terdapat jadual <kod>mesej</kod>
<pre class="brush:php;toolbar:false;">Id Name Other_Columns
-----------------------
1 A A_data_1
2 A A_data_2
3 A A_data_3
4 B B_data_1
5 B B_data_2
6 C C_data_1</pre>
<p>Jika saya menjalankan pertanyaan <kod>pilih * daripada kumpulan mesej mengikut nama</kod>, saya akan mendapat keputusan sebagai:</p>
<pre class="brush:php;toolbar:false;">1 A A_data_1
4 B B_data_1
6 C C_data_1</pre>
<p>Apakah pertanyaan yang akan mengembalikan hasil berikut? </p>
<pre class="brush:php;toolbar:false;">3 A A_data_3
5 B B_data_2
6 C C_data_1</pre>
<p>Iaitu, rekod terakhir dalam setiap kumpulan hendaklah dikembalikan. </p>
<p>Pada masa ini, ini ialah pertanyaan yang saya gunakan: </p>
<pre class="brush:php;toolbar:false;">SELECT
*
DARI (PILIH
*
DARIPADA mesej
PESANAN OLEH id DESC) SEBAGAI x
KUMPULAN MENGIKUT nama</pra>
<p>Tetapi ini nampaknya tidak cekap. Adakah terdapat cara lain untuk mencapai hasil yang sama? </p>
UPD: 31-03-2017, versi 5.7.5 MySQL mendayakan suis ONLY_FULL_GROUP_BY secara lalai (jadi pertanyaan GROUP BY bukan deterministik dilumpuhkan). Selain itu, mereka mengemas kini pelaksanaan GROUP BY dan penyelesaian mungkin tidak berfungsi seperti yang diharapkan walaupun dengan suis dilumpuhkan. Perlu menyemaknya.
Penyelesaian Bill Karwin di atas berfungsi dengan baik apabila kiraan item dalam kumpulan agak kecil, tetapi prestasi pertanyaan menjadi buruk apabila kumpulan agak besar, kerana penyelesaiannya memerlukan kira-kira
n*n/2 + n/2
of onlyIS NULL
perbandingan.Saya membuat ujian saya pada jadual InnoDB sebanyak
18684446
rows with1182
groups. The table contains testresults for functional tests and has the(test_id, request_id)
as the primary key. Thus,test_id
is a group and I was searching for the lastrequest_id
for eachtest_id
.Penyelesaian Bill telah berjalan selama beberapa jam pada dell e4310 saya dan saya tidak tahu bila ia akan selesai walaupun ia beroperasi pada indeks liputan (oleh itu
using index
dalam EXPLAIN).Saya mempunyai beberapa penyelesaian lain berdasarkan idea yang sama:
(group_id, item_value)
pair is the last value within eachgroup_id
, that is the first for eachgroup_id
jika kita berjalan melalui indeks dalam tertib menurun;3 Cara MySQL Menggunakan Indeks ialah artikel yang bagus untuk membantu anda memahami beberapa butiran.
Penyelesaian 1
Ini sangat pantas, mengambil masa kira-kira 0.8 saat pada baris 18J+ saya:
Jika anda ingin menukar susunan kepada ASC, masukkannya dalam subkueri yang hanya mengembalikan id dan gunakannya sebagai subkueri untuk menyertai lajur yang lain:
Ini mengambil masa kira-kira 1.2 saat untuk data saya.
Penyelesaian 2
Ini satu lagi penyelesaian yang mengambil masa kira-kira 19 saat untuk jam tangan saya:
Ia juga mengembalikan ujian dalam susunan menurun. Ia jauh lebih perlahan kerana ia melakukan imbasan indeks penuh, tetapi ia memberi anda idea tentang cara untuk mengeluarkan N baris maksimum untuk setiap kumpulan.
Kelemahan pertanyaan ini ialah cache pertanyaan tidak boleh menyimpan hasil cariannya.
MySQL 8.0 kini menyokong fungsi tetingkap, seperti hampir semua pelaksanaan SQL yang popular. Menggunakan sintaks standard ini, kita boleh menulis sehingga n pertanyaan bagi setiap kumpulan:
Ini dan kaedah mencari yang lain bilangan maksimum baris yang dikumpulkan diterangkan dalam manual MySQL.
Inilah jawapan asal yang saya tulis untuk soalan ini pada tahun 2009:
Saya menulis penyelesaian seperti ini:
Berkenaan prestasi, satu penyelesaian mungkin lebih baik bergantung pada sifat data. Oleh itu, anda harus menguji kedua-dua pertanyaan dan menggunakan pertanyaan yang mempunyai prestasi yang lebih baik berdasarkan pangkalan data anda.
Sebagai contoh, saya mempunyai salinan StackOverflow August dump Saya akan menggunakannya untuk menanda aras Terdapat 1,114,357 baris dalam jadual
Posts
Ini berjalan pada MySQL 5.0.75 GHz saya. .Saya akan menulis pertanyaan untuk mencari siaran terkini untuk ID pengguna yang diberikan (saya).
Mula-mula menggunakan teknik ditunjukkan oleh @Eric dengan
GROUP BY
dalam subkueri:Malah
EXPLAIN
analisis mengambil masa lebih 16 saat:Kini hasilkan hasil pertanyaan yang sama menggunakan teknik saya dengan
LEFT JOIN
:Analisis
EXPLAIN
menunjukkan bahawa kedua-dua jadual boleh menggunakan indeksnya:Berikut ialah DDL untuk jadual
Posts
saya:Nota kepada pengulas: Jika anda ingin menjalankan penanda aras lain menggunakan versi MySQL yang berbeza, set data yang berbeza atau reka bentuk jadual yang berbeza, sila lakukan sendiri. Saya telah menunjukkan teknik di atas. Stack Overflow ada di sini untuk menunjukkan kepada anda cara melakukan kerja pembangunan perisian, bukan untuk melakukan semua kerja untuk anda.