v MySQL, historicky GROUP BY byl použit k zajištění třídění stejně. Pokud dotaz zadal skupinu podle, výsledek byl seřazen, jako by byl v dotazu přítomen příkaz podle.
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> INSERT INTO t VALUES (4,1),(3,2),(1,4),(2,2),(1,1),(1,5),(2,6),(2,1),(1,3),(3,4),(4,5),(3,6);
Query OK, 12 řádků postižených (0,02 sec)
Záznamy: 12 Duplikáty: 0 Varování: 0
mysql-5.7> SELECT id, SUM(cnt) FROM t GROUP BY id;
+——+———-+
| id | SUM(cnt) |
+——+———-+
| 1 | 13 |
| 2 | 9 |
| 3 | 12 |
| 4 | 6 |
+——+———-+
, 4 řádky v souboru (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 řádky v souboru, 1 pruhu (0,00 sec)
|
To se změnilo v 8.0, jak to již podporuje buď implicitní nebo explicitní řazení pro SKUPINY. V tomto blogu, vysvětlím, proč se tato změna stala nezbytnou, a také práce vykonaná jako předchůdce této změny.
GROUP by v MySQL
Chcete-li seskupit sadu řádků, MySQL optimizer zvolí různé metody. Jedním z nich je třídit řádky před jejich seskupením. To usnadňuje seskupování jedné skupiny za druhou. Také se stává levným, pokud existuje index, který by mohl být použit k získání tříděných řádků. Pokud neexistuje žádný index, MySQL optimizer by se mohl ještě rozhodnout provést externí (filesort) třídění před seskupením.
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> VYSVĚTLIT VYBERTE SQL_BIG_RESULT id, SUM(cnt) FROM t GROUP BY id \G
*************************** 1. řádek ***************************
id: 1
select_type: JEDNODUCHÉ
tabulka: t
oddíly: NULL
objednávky:
possible_keys: NULL
klíč: 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
type: index
possible_keys: id
klíč: id
key_len: 10
ref: NULL
řádky: 12
filtruje: 100.00
Extra: Použití index
1 řádek v souboru, 1 pruhu (0,00 sec)
|
Jak je vidět v příkladu, před přidáním indexu do tabulky, MySQL používá externí třídění udělat GROUP BY. Pro příklad dotazu jsem vynutil plán pomocí SQL_BIG_RESULT (protože MySQL si tento plán nevybere pro datovou sadu, kterou máme). MySQL by však tento plán použil ke seskupení bez indexu, aby získal tříděné řádky a použití dočasné tabulky se stává nákladným kvůli velkému počtu skupin. Jakmile je index přidán, uchýlí se k použití indexu do skupiny podle.
ale řazení řádků před seskupením není nutností. Optimalizátor se může rozhodnout, že k tomu využije dočasnou tabulku. Každý řádek v této tabulce by byl seskupený řádek a s každým příchozím řádkem se aktualizuje řádek odpovídající této skupině v tabulce. Třídění zde není potřeba. Nicméně, jak se očekávalo, že skupina by v MySQL bude třídit, byla nucena třídit seskupené řádky i v tomto případě .
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;
Query OK, 0 řádků postižených (0.01 sec)
Záznamů: 0 Duplikáty: 0 Varování: 0
mysql-5.7> VYSVĚTLIT SELECT id, SUM(cnt) FROM t GROUP BY id \G
*************************** 1. řádek ***************************
id: 1
select_type: JEDNODUCHÉ
tabulka: t
oddíly: NULL
typ:
possible_keys: NULL
klíč: NULL
key_len: NULL
ref: NULL
řádky: 12
filtruje: 100.00
Extra: Použití dočasné; Using filesort
1 řádek v souboru, 1 pruhu (0,00 sec)
|
V příkladu dotazu, můžeme vidět, že i když dočasné tabulky se používá, MySQL stále nemá vnější třídění. Uživatelé by museli explicitně zadat pořadí podle NULL, aby MYSQL věděli, že skupina nemusí třídit. Proto byla potřeba nestandardní syntaxe (ORDER BY NULL), aby se zabránilo účinku jiného nestandardního rozšíření (GROUP by sorting). Teď je to mnohem čistší, když jsme odstranili ten nepořádek.
odstranění implicitního třídění pro skupinu
nějaký čas zpět jsem se snažil opravit chybu 71804. Reportér očekával, že MySQL nebude dělat zbytečné třídění souborů, které dělá pro skupinu podle. Pokus o opravu chyby nás přiměl uvědomit si, že optimalizace této konkrétní situace není příliš přímočará kvůli podpoře implicitního a explicitního třídění této skupiny poskytnutými. Takže jsme dospěli k závěru, že předtím, než by tato optimalizace mohla být provedena, měli bychom re-factoring kód vztahující se k třídění pro GROUP BY.
prvním krokem bylo odstranění implicitního třídění pro GROUP BY. Jak je uvedeno v uživatelské příručce zde, bylo rozhodnuto o jeho odstranění . Bylo provedeno jako součást funkce sestupného indexu v 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> SELECT id, SUM(cnt) FROM t GROUP BY id;
+——+———-+
| id | SUM(cnt) |
+——+———-+
| 4 | 6 |
| 3 | 12 |
| 1 | 13 |
| 2 | 9 |
+——+———-+
, 4 řádky v souboru (0,00 sec)
mysql> VYSVĚTLIT SELECT id, SUM(cnt) FROM t GROUP BY id \G
*************************** 1. řádek ***************************
id: 1
select_type: SIMPLE
tabulka: t
oddíly: NULL
typ:
possible_keys: NULL
klíč: NULL
key_len: NULL
ref: NULL
řádky: 12
filtruje: 100.00
Navíc: Pomocí dočasné
1 řádek v souboru, 1 pruhu (0,00 sec)
|
Jak je vidět na příkladu výše, řazení se neprovádí pro dotaz. Výsledkem je, že seskupené řádky nejsou v konečném výsledku seřazeny. Pokud uživatelé potřebují seřazené řádky, musí v dotazu zadat ORDER BY.
v MySQL 5.7 a níže uvedené verze najdou uživatelé v příručce následující varování.
„GROUP BY
implicitně druhy ve výchozím nastavení (to znamená, že v nepřítomnosti ASC
nebo DESC
specifikace GROUP BY
sloupce). Nicméně, se spoléhat na implicitní GROUP BY
třídění (to znamená, že třídění v nepřítomnosti ASC
nebo DESC
specifikace) nebo explicitní řazení pro GROUP BY
(to je, pomocí explicitní ASC
nebo DESC
specifikace GROUP BY
sloupce) je zastaralé. Pro vytvoření daného pořadí řazení zadejte klauzuli ORDER BY
. „
odstranění explicitního třídění pro skupinu
když došlo k odstranění explicitního třídění, bylo to trochu složitější. Nemohli jsme jej odstranit, pokud MySQL podporované pořadí s kumulativní. Kumulativní s objednávkou nebylo povoleno v MySQL 5.7 a starších verzích. Tak, jako alternativa, by uživatelé použít GROUP BY ASC/DESC, aby si seřazená data s KUMULATIVNÍ (i když třídění bylo velmi omezující se super agregované řádky vždy umístěny po řadách používá pro výpočet je v případě ASC a naopak pro DESC). Toto omezení jsme museli zrušit, než jsme odstranili podporu pro explicitní třídění pro skupinu podle.
MySQL nyní umožňuje objednat pomocí kumulativní. Podrobně jsem vysvětlil, jak toto zlepšení využít. Jak je vysvětleno ve stejném blogu, pokud uživatelé chtějí přesně stejné pořadí třídění null jako u MySQL 5.7 pro kumulativní, měli by použít funkci seskupení() k opětovnému zápisu dotazu jednoduchým způsobem.
takže ve zkratce jsme udělali následující věci jako prekurzory k odstranění explicitní třídění pro GROUP BY.
1. Přidání funkce seskupení ()
2. Odstranění implicitního třídění pro skupinu
3. Povolení pořadí pomocí kumulativní
a nakonec jsme odstranili explicitní třídění pro skupinu podle V MySQL 8.0.13.
požádali jsme o stanovisko obce před časem. Došli jsme k závěru, že uživatelé, kteří si byli vědomi tohoto nestandardního rozšíření, které MySQL poskytl, byli v pořádku, když to zmizelo.
závěr
přestože máme ještě nějakou práci, než opravíme chybu 71804, jsme rádi,že jsme to udělali. Prosím, dejte nám vědět své myšlenky. Díky za použití MySQL!