Autor | Zpráva | ||
---|---|---|---|
Foi Profil |
Mám dotaz:
SELECT * FROM statuses AS `s` WHERE (s.account_id IN(SELECT `f`.`follows_id` AS `f_follows_id` FROM followers AS `f` WHERE f.account_id = '75') OR s.account_id = '75') ORDER BY s.created DESC LIMIT 0, 10 A indexy u created, zkoušel jsem i dát (created, account_id), ale výsledek je stále 15 ms. Tabulka statuses má jen 2 500 položek a tabulka followers má jen 5 500. Zdá se mi to přehnaný čas na to kolik to má záznamů. Explain dotazu tady: ![]() Další jednoduchý update trvá 10ms UPDATE accounts SET last_visit = '2019-08-05 14:02:36' WHERE id = '75' je to normální?
|
||
Tomášeek Profil |
#2 · Zasláno: 5. 8. 2019, 14:48:52
Foi:
A co takhle pracovat s číslem jako s číslem? Tedy místo '75' používat 75 . Nepomůže?
|
||
Foi Profil |
#3 · Zasláno: 5. 8. 2019, 15:05:23
Nene, výsledky časů jsou stejné :/
|
||
ttttt Profil * |
#4 · Zasláno: 5. 8. 2019, 15:41:26
Foi:
„Další jednoduchý update trvá 10ms. Je to normální?“ Jo, myslím, že je. Zkusil jsem UPDATE nad tabulkou s pěti záznamy na PC s HDD (ne SSD) a dostávám časy okolo 40 - 50 ms. Postgres na serveru 1,5 ms. Tady má někdo podobný dotaz na 55 000 záznamech a čas 120 ms. 10 ms není čas, u kterého bych si řekl, že musí být nutně něco špatně, záleží s jakým nastavením a na čem to spouštíš. |
||
Tomášeek Profil |
#5 · Zasláno: 5. 8. 2019, 15:51:12
ttttt:
No, ono 10ms na tak triviálním dotazu je docela dost. Vezmi si, že máš e-shop, kde se produkty nedají natáhnout jedním dotazem (parametry, varianty, ...), máš vícero jazykových mutací (dotaz do slovníku), samozřejmě kategorie, hodnocení produktů, a milion dalších věcí, které se běžně načítají... Pak 10ms na takto jednoduchý dotaz je skutečně dost. Ale je fakt, že nevíme, na čem to Foi pouští a může to být jen pomalým strojem. |
||
Keeehi Profil |
#6 · Zasláno: 5. 8. 2019, 17:48:25
On je nějaký minimální čas, který zabere režije okolo spuštění jakehokoli dotazu. Zrovna v tomto případě to může být těch 10ms a pod to se na té dané konfiguraci nedá dostat. Na druhou stranu těch 10 - 15 ms to může držet klidně třeba od toho tisíce do milionu řádků.
|
||
blaaablaaa Profil |
#7 · Zasláno: 6. 8. 2019, 08:05:54
Tomášeek:
Tak všechna tahle data snad na větším projektu netaháš vždy z db, ale z cache. |
||
Kajman Profil |
#8 · Zasláno: 6. 8. 2019, 08:30:39
Mysql mívala dříve problémy s dotazy typu sloupec in (select), kdy plánovač občas dělal vnitřní select pro každý řádek, i když tam nebyla použita korelace. Pak bylo vhodnější to přespat na join. Ale podle explainu to vypadá, že tady se tak neděje.
Pro porovnání rychlosti si můžete změřit obyčejné dotazy. SELECT SQL_NO_CACHE `f`.`follows_id` FROM followers AS `f` WHERE f.account_id = 75 SELECT SQL_NO_CACHE * FROM statuses AS `s` WHERE s.account_id = 75 |
||
Foi Profil |
Kajman časy jsou takové:
1) 0.0024s 2) 0.0022s Původní dotaz 0.025 Nemá to smysl řešit a při nejhorším uvažovat o lepším stroji. Myslel jsem, že mám chybu někde v kódu/klíčích, ale asi ne. |
||
Kajman Profil |
Tipnul bych, že nejpomalejší na tom bude to řazení, protože index se použite na where, ale řazení se musí udělat bez pomoci indexu. Je divné, že to v explainu není poznat.
Podle názvů indexů se moc nedá poznat, co tam je za sloupce a jakého typu indexy jsou. Pomohly by výsledky show create table statuses; show create table followers; Jak jsou rychlé tyto dotazy a kolik vrací řádků bez limitu? SELECT SQL_NO_CACHE s.* FROM statuses AS s WHERE s.account_id IN(SELECT `f`.`follows_id` AS `f_follows_id` FROM followers AS `f` WHERE f.account_id = 75) LIMIT 0, 10; SELECT SQL_NO_CACHE s.* FROM statuses AS s JOIN followers AS f ON s.account_id=f.follows_id WHERE f.account_id = 75 LIMIT 0, 10; SELECT SQL_NO_CACHE s.* FROM statuses AS s JOIN followers AS f ON s.account_id=f.follows_id WHERE f.account_id = 75 ORDER BY s.created DESC LIMIT 0, 10; |
||
Foi Profil |
#11 · Zasláno: 9. 8. 2019, 11:28:52
1) Table statuses (názvy sloupců zkrácené, indexu není moc, protože optimalizuji, až když je problém s časem), používám doctrine
CREATE TABLE `statuses` ( `id` int(11) NOT NULL AUTO_INCREMENT, `created` datetime NOT NULL, `content` longtext COLLATE utf8_unicode_ci NOT NULL, `account_id` int(11) DEFAULT NULL, `category_id` int(11) DEFAULT NULL, `status_id` int(11) DEFAULT NULL, `link_metadata_id` int(11) DEFAULT NULL, PRIMARY KEY (`id`), KEY `IDX_4BF01E119B6B5FBA` (`account_id`), KEY `IDX_4BF01E116BF700BD` (`status_id`), KEY `IDX_4BF01E1112469DE2` (`category_id`), KEY `IDX_4BF01E11111E650A` (`link_metadata_id`), KEY `created_idx` (`created`), CONSTRAINT `FK_4BF01E11111E650A` FOREIGN KEY (`link_metadata_id`) REFERENCES `link_metadata` (`id`) ON DELETE SET NULL, CONSTRAINT `FK_4BF01E1112469DE2` FOREIGN KEY (`category_id`) REFERENCES `news_categories` (`id`) ON DELETE SET NULL, CONSTRAINT `FK_4BF01E116BF700BD` FOREIGN KEY (`status_id`) REFERENCES `statuses` (`id`) ON DELETE CASCADE, CONSTRAINT `FK_4BF01E119B6B5FBA` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB AUTO_INCREMENT=18298 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 2) followers CREATE TABLE `followers` ( `account_id` int(11) NOT NULL, `follows_id` int(11) NOT NULL, PRIMARY KEY (`account_id`,`follows_id`), KEY `IDX_8408FDA79B6B5FBA` (`account_id`), KEY `IDX_8408FDA725215351` (`follows_id`), CONSTRAINT `FK_8408FDA725215351` FOREIGN KEY (`follows_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE, CONSTRAINT `FK_8408FDA79B6B5FBA` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci 1) 0.0021-0.0029, vrací 0 řádků 2) 0.0019-0.0037, vrací 0 řádků 3) 0.0023-0.0040, vrací 0 řádků Když to provedu na několika tisících záznamech, tak jen 3) vzroste na 0.0310 Jakmile dodám u 1) to OR s.account_id = 75, tak najednou stoupne o 10 násobek na 0.0256 - 0.0350, i když je 0 záznamů Takže problémem asi bude OR s.account_id a ORDER BY s.created
|
||
Kajman Profil |
#12 · Zasláno: 9. 8. 2019, 12:23:43
Testovat rychlost dotazů s řazením, co vrací nula řádků, nedává moc smysl.
Ten or tam může být problematický, často se to vnitřně rozloží na union dotazy, tak by se to dalo rozložit ručně a využít toho limitu, aby se union dělal až na těch 10 řádků. Ale pochybuji, že to bude rychlejší. Plánovač by to měl zvládnou sám. SELECT * FROM ((SELECT s.* FROM statuses AS s WHERE s.account_id IN(SELECT f.follows_id FROM followers AS f WHERE f.account_id = 75) ORDER BY s.created DESC LIMIT 10) -- pri strankovani menit limit 10 20 30 40... UNION (SELECT s.* FROM statuses AS s WHERE s.account_id = 75 ORDER BY s.created DESC LIMIT 10) -- pri strankovani menit limit 10 20 30 40... ) t ORDER BY t.created DESC LIMIT 0, 10 -- pri strankovani menit offset 0 10 20 30... Také můžete zkusit udělat u tabulky statuses dvousloupcový index (`account_id`, `created`) - on pomůže přímo jen v druhém pododtaze, ale v prvním možná bude stačit číst pro řazení hodnotu created z indexu a až těch 10 řádků by se četlo z tabulky.
Nebo si můžete určit, že v tabulce followers bude mít každý uživatel sám sebe a pokud tam tedy bude řádek (75,75), nemusíte OR psát :-) |
||
Foi Profil |
#13 · Zasláno: 9. 8. 2019, 12:42:25
Kajman Děkuji za všechno. Dotaz je stejně výkonný jako OR. Dvousloupcový index jsem zkoušel viz první post bez výsledku. Vypadá to tak, že to nechám a třeba v budoucnu to vyřeší uvnitř mysql
|
||
Kajman Profil |
#14 · Zasláno: 9. 8. 2019, 12:47:17
Foi:
„Dvousloupcový index jsem zkoušel viz první post bez výsledku.“ Ale v obráceném pořadí sloupců. Není to stejné. |
||
Foi Profil |
#15 · Zasláno: 9. 8. 2019, 13:13:10
Kajman:
Z 24 ms na 19ms změna. Musím si nastudovat mnoho informací o databázích |
||
Časová prodleva: 6 let
|
0