în MySQL, istoric grup de a fost folosit pentru a oferi sortare, de asemenea. În cazul în care o interogare specificată grup de, rezultatul a fost sortat ca în cazul în care ordinea de a fost prezent în interogare.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
mysql-5.7> CREATE TABLE t (id INTEGER, cnt INTEGER);
Query OK, 0 rows affected (0.03 sec)
mysql-5.7 > introduceți în valorile t(4,1),(3,2),(1,4),(2,2),(1,1),(1,5),(2,6),(2,1),(1,3),(3,4),(4,5),(3,6);
interogare OK, 12 rânduri afectate (0,02 sec)
înregistrări: 12 duplicate: 0 avertismente: 0
mysql-5.7> selectați id, sumă(cnt) din grupul t după id;
+——+———-+
| id / SUM (cnt) /
+——+———-+
| 1 | 13 |
| 2 | 9 |
| 3 | 12 |
| 4 | 6 |
+——+———-+
4 rânduri în set (0.00 sec)
|
MySQL here implicitly sorts the results from GROUP BY (i.e. in the absence of ASC
or DESC
designators for GROUP BY
columns ).
MySQL also supported explicit sorting with GROUP BY (i.e. by using explicit ASC
or DESC
designators for GROUP BY
columns).
1
2
3
4
5
6
7
8
9
10
|
mysql-5.7> SELECT id, SUM(cnt) FROM t GROUP BY id DESC;
+——+———-+
| id / SUM (cnt) /
+——+———-+
| 4 | 6 |
| 3 | 12 |
| 2 | 9 |
| 1 | 13 |
+——+———-+
4 rânduri în set, 1 avertisment (0,00 sec)
|
Acest lucru s-a schimbat în 8.0, deoarece nu mai acceptă sortarea implicită sau explicită pentru GROUP BY. În această postare pe blog, voi explica de ce această schimbare a devenit necesară și, de asemenea, munca depusă ca precursor al acestei schimbări.
GROUP BY în MySQL
pentru a grupa un set de rânduri, MySQL optimizer alege diferite metode. Una dintre ele este să sortați rândurile înainte de a le grupa. Acest lucru facilitează gruparea unui grup după altul. De asemenea, devine ieftin dacă există un index care ar putea fi folosit pentru a obține rânduri sortate. Dacă nu există index, MySQL optimizer ar putea decide în continuare să facă sortare externă (filesort) înainte de grupare.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
MySQL-5.7> explica selectați sql_big_result id, suma(CNT) din grupul t de ID \g
*************************** 1. rând ***************************
id: 1
select_type: simplu
tabel: t
partiții: NULL
ordine: toate
possible_keys: NULL
cheie: NULL
key_len: null
ref: NULL
rows: 12
filtered: 100.00
Extra: Using filesort
1 row in set, 1 warning (0.01 sec)
mysql-5.7> ALTER TABLE t ADD INDEX (id, cnt);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql-5.7> EXPLAIN SELECT id, SUM(cnt) FROM t GROUP BY id \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: t
partitions: NULL
tip: index
possible_keys: id
cheie: id
key_len: 10
ref: null
rânduri: 12
filtrat: 100.00
Extra: folosind index
1 rând în set, 1 avertisment (0,00 sec)
|
după cum se vede în exemplu, înainte de a adăuga index la tabel, MySQL folosește sortarea externă pentru a face grup după. Pentru interogarea de exemplu, am forțat planul utilizând SQL_BIG_RESULT (deoarece MySQL nu va alege acest plan pentru setul de date pe care îl avem). Dar MySQL ar folosi acest plan pentru a grupa în absența unui index pentru a obține rânduri sortate și utilizarea tabelului temporar devine costisitoare din cauza numărului mare de grupuri. Odată ce indicele este adăugat, recurge la utilizarea indexului pentru a face grup de.
dar sortarea rândurilor înainte de grupare nu este o necesitate. Optimizer poate decide să facă uz de un tabel temporar pentru a face acest lucru. Fiecare rând din acest tabel ar fi un rând grupat și cu fiecare rând de intrare, rândul corespunzător acelui grup din tabel este actualizat. Sortarea nu este necesară aici. Cu toate acestea, așa cum se aștepta ca GROUP BY în MySQL să sorteze, a fost forțat să sorteze rândurile grupate chiar și în acest caz .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
MySQL-5.7> ALTER TABLE t DROP INDEX id;
interogare OK, 0 rânduri afectate (0,01 sec)
înregistrări: 0 duplicate: 0 avertismente: 0
mysql-5.7> explicați selectați id, sumă(cnt) din grupul t de id \G
*************************** 1. rând ***************************
id: 1
select_type: simplu
tabel: t
partiții: NULL
Tip: toate
possible_keys: NULL
cheie: NULL
key_len: null
ref: null
rânduri: 12
filtrat: 100.00
Extra: utilizarea temporară; utilizarea filesort
1 rând în set, 1 avertisment (0.00 sec)
|
în interogarea exemplu, putem vedea că, deși temporar tabelul este utilizat, MySQL face încă sortare externă. Utilizatorii ar trebui să specifice în mod explicit ORDER BY NULL pentru a anunța MYSQL că GROUP BY nu trebuie să sorteze. Deci, a fost necesară o sintaxă non-standard (ordine prin nul) pentru a contracara efectul unei alte extensii non-standard (grup prin sortare). Este mult mai curat acum că am eliminat această mizerie.
eliminarea sortare implicită pentru grup de
ceva timp în urmă am fost încercarea de a repara bug 71804. Reporterul se aștepta ca MySQL să nu facă sortarea inutilă a fișierelor pe care o făcea pentru GROUP BY. Încercarea de a face un patch pentru bug ne-a făcut să ne dăm seama că optimizarea acestei situații particulare nu este foarte directă din cauza suportului pentru sortarea implicită și explicită a acelui grup furnizat. Așa că am ajuns la concluzia că înainte de această optimizare ar putea fi făcut, ar trebui să fie re-factoring cod legate de sortare pentru grup de.
primul pas în a face acest lucru a fost eliminarea sortării implicite pentru grup după. După cum sa menționat în manualul de utilizare aici, s-a decis eliminarea suportului pentru acesta cu ceva timp în urmă . Acesta a fost realizat ca parte a caracteristicii index descendent în 8.0.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
mysql > selectați id, sumă (cnt) din grupul t după id;
+——+———-+
| id / SUM (cnt) /
+——+———-+
| 4 | 6 |
| 3 | 12 |
| 1 | 13 |
| 2 | 9 |
+——+———-+
4 rânduri în set (0,00 sec)
mysql> explicați selectați id-ul, suma(cnt) din grupul t prin id \G
*************************** 1. rând ***************************
id: 1
select_type: simplu
tabel: t
partiții: NULL
Tip: toate
possible_keys: null
cheie: null
key_len: null
ref: null
rânduri: 12
filtrat: 100.00
Extra: folosind temporar
1 rând în set, 1 avertisment (0,00 sec)
|
după cum se vede în exemplul de mai sus, sortarea nu este efectuată pentru interogare. Ca rezultat, rândurile grupate nu sunt sortate în rezultatul final. Dacă utilizatorii au nevoie de rânduri sortate, trebuie să specifice ORDER BY în interogare.
în MySQL 5.7 și versiunile de mai jos, utilizatorii găsesc următorul avertisment în manual.
„GROUP BY
Sortează implicit în mod implicit (adică în absențaASC
sauDESC
desemnatori pentruGROUP BY
coloane). Cu toate acestea, bazându-se pe GROUP BY
sortare implicită (adică sortare în absența ASC
sau DESC
sortare explicită pentru GROUP BY
(adică prin utilizarea explicită ASC
sau DESC
desemnatori pentru GROUP BY
coloane) este depreciat. Pentru a produce o anumită ordine de sortare, furnizați o clauzăORDER BY
. „
eliminarea sortării explicite pentru grup prin
când a venit vorba de eliminarea sortării explicite, a fost un pic mai dificil să o faci. Nu am putut să o eliminăm decât dacă MySQL acceptă comanda cu ROLLUP. ROLLUP cu ORDER BY nu a fost permis în MySQL 5.7 și versiunile anterioare. Deci, ca alternativă, utilizatorii ar folosi GROUP BY ASC / DESC pentru a obține date sortate cu ROLLUP (deși sortarea a fost foarte restrictivă, cu rânduri super agregate plasate întotdeauna după rândurile utilizate pentru a le calcula în cazul ASC și invers pentru DESC). A trebuit să ridicăm această limitare înainte de a elimina suportul pentru sortarea explicită pentru GROUP BY.
MySQL permite acum comanda cu ROLLUP. Am explicat în detaliu cu privire la modul de a face uz de această îmbunătățire aici. După cum se explică în același blog, dacă utilizatorii doresc exact aceeași ordine de sortare a Nulurilor ca cea a MySQL 5.7 pentru ROLLUP, ar trebui să utilizeze funcția GROUPING() pentru a rescrie interogarea într-un mod simplu.
Deci, pe scurt, am făcut următoarele lucruri ca precursori pentru eliminarea sortare explicită pentru grup de.
1. Adăugarea funcției grupare ()
2. Eliminarea sortării implicite pentru grup cu
3. Permițând comanda cu ROLLUP
și în cele din urmă am eliminat sortarea explicită pentru GROUP BY în MySQL 8.0.13.
am cerut opinia comunităților cu ceva timp în urmă. Am ajuns la concluzia că utilizatorii care au fost conștienți de această extensie non-standard pe care MySQL a furnizat-o au fost bine să dispară.
concluzie
deși mai avem ceva de lucru înainte de a repara bug-ul 71804, suntem fericiți că am făcut acest lucru. Vă rugăm să ne spuneți gândurile tale. Vă mulțumim pentru utilizarea MySQL!