Autor Zpráva
Kcko
Profil
Našel jsem moc pěkný blog, kde se do podrobna rozebírají advanced věci i starší, ale třeba složitější funkce a postupy.

learnsql.com

Jen tak ze zajímavosti jsem si přečetl rozbor funkce COUNT a zaujalo mě následující:

- learnsql.com/blog/sql-count-function
- learnsql.com/blog/difference-between-count-distinct

Autor tvrdí, že
následující příkazy jsou ekvivalentní a je jen pohádka, že si někdo myslel něco jiného (i já)

SELECT COUNT(*) -- známá věc
SELECT COUNT(1) -- méně známá, používám a žil jsem v domnění, že to bude o fous rychlejší|
SELECT COUNT(-50) -- totální blbost, ale je to stejné jako předchozí
SELECT COUNT('cussssss jak se mas') -- totalni blbost, ale opět stejné

No budiž, budu tomu věřit, možná se COUNT(1) týkal starších verzí MYSQL.

Ale co mě zaujalo víc:

SELECT COUNT(CASE WHEN order_price > 1000 THEN 1 END)
AS significant_orders
FROM orders;

V této ukázce, přesunul filtrování přímo do COUNT funkce, já bych to dal do WHERE

Zkusil jsem si na to svojí DB a výsledkem je



vs



Co je zajímavé? Nepoužije se index ani v 1 případě, i když na sloupci je (takže bych to čekal)

a v extra popisu je SELECTED OPTIMIZED AWAY což podle vysvětlení je to nejlepší a lepší už to nejde (tj. rychlejší než když to strčím do WHERE)

Používate to tak? Co si o tom myslíte?

@Kajman? ;-)
tttttt
Profil *
Myslím si, že si myslíš, že ty dva dotazy dávají stejný výsledek.

MariaDB [test]> select SQL_NO_CACHE count(*) from tt where val > 50000;
+----------+
| count(*) |
+----------+
|   713945 |
+----------+
1 row in set (0.098 sec)

MariaDB [test]> select SQL_NO_CACHE count(if( val > 50000, 1, 0)) from tt;
+-------------------------------+
| count(if( val > 50000, 1, 0)) |
+-------------------------------+
|                       1428868 |
+-------------------------------+
1 row in set (0.201 sec)


A ten explain dostávám také jiný

MariaDB [test]> explain select count(if( val > 50000, 1, 0)) from tt;
+------+-------------+-------+-------+---------------+-------+---------+------+---------+-------------+
| id   | select_type | table | type  | possible_keys | key   | key_len | ref  | rows    | Extra       |
+------+-------------+-------+-------+---------------+-------+---------+------+---------+-------------+
|    1 | SIMPLE      | tt    | index | NULL          | idxtt | 5       | NULL | 1426920 | Using index |
+------+-------------+-------+-------+---------------+-------+---------+------+---------+-------------+
1 row in set (0.000 sec)

mysql  Ver 15.1 Distrib 10.11.2-MariaDB, for Linux (x86_64) using readline 5.1

Může to být o verzích databáze.

COUNT(CASE …) a COUNT(if( val > 50000, 1, 0)) není ekvivalentní. Ten IF vždy vrací non-null, takže dělá to samé jako COUNT(1). Nejspíš jsi tam chtěl mít SUM. Pokud MySQL dokáže COUNT v konstantím čase, pak nepotřebuje číst tabulku a ten explain dává smysl. Přijde mi to podezřelé, většinou je potřeba kvůli transakcím koukat do dat. Ale MySQL už nějakou dobu nesleduju.
Kajman
Profil
Kcko:
Nepoužije se index ani v 1 případě

Podle názvu indexu je sloupec použitý pro filtr až na třetím místě a nelze tedy podle něj rychle hledat. Jen se může číst z indexu místo z tabulky.

Pro jeden výraz count nebo sum s filtrovacím výrazem uvnitř nedávají moc smysl a pochybuji, že budou rychlejší. Spíše se to používá pro generování více sloupců najednou, pokud databáze nepodporuje PIVOT operátor.
Kcko
Profil
tttttt:
Ahoj, máš pravdu, aby to dávalo stejný výsledek musí se použít SUM (protože to je skutečný součet), COUNT spočítá všechny řádky s nenulovou hodnotou (takže i s tou nulou, takže veme celou tabulku), takže se čísla liší.

takže bud takto

SELECT SQL_NO_CACHE COUNT(IF(datum_vytvoreni < '2020-08-17', 1, NULL)) FROM clanky
nebo
SELECT SQL_NO_CACHE COUNT(CASE WHEN datum_vytvoreni < '2020-08-17' THEN  1 ELSE NULL END) FROM clanky

pak to počítá korektně jako count(*) s WHERE


Kajman:
Pořádně sem si to vyzkoušel (dopoledne sem to zkoušel na MySQL 5.6 a ted na Maria DB) a
count ve where je znatelně rychlejší než filtrovací výraz v COUNT/SUM


0,002s vs 0,036


EDIT
pustil sem to asi 20x za sebou a ty časy jsou pořád ~ 0,015s (v obou případech)

Co je prosím PIVOT operátor?
Kajman
Profil
Když zkusím dotaz s count case na innodb tabulce s dvěma miliony řádků, tak trvá bez ohledu na hranici kolem 0,7 s. Při použití ve where se rychlost pohybuje mezi 0,001 až 0,6 s podle toho, kolik hranice omezí řádků (tedy ve where se použije částečně index).

A ten PIVOT zjednodušuje psaní sum case a podobných kombinací přehlednější syntaxí
- bez podpory
learnsql.com/blog/useful-sql-patterns-pivoting
- s podporou
www.oracle.com/technical-resources/articles/database/sql-11g-pivot.html
learn.microsoft.com/en-us/sql/t-sql/queries/from-using-pivot-and-unpivot
Kcko
Profil
Kajman:
Jo tak, vím co je pivotní tabulka a marně jsem hledal v mysql co je to Pivot operátor ;).

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0