Autor | Zpráva | ||
---|---|---|---|
abc Profil |
#1 · Zasláno: 1. 6. 2015, 19:21:18
Ahoj,
mám takový drobný problém s jedním výkonností jednoho view. Nevěděl by někdo, jak to zrychlit? Děkuji. EXPLAIN vypadá takto: id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY c range comment_user_id_fkey,date date 9 NULL 55794 Using where; Using temporary; Using filesort 1 PRIMARY u eq_ref PRIMARY PRIMARY 4 c.user_id 1 Using where 2 DEPENDENT SUBQUERY l ref user_logs_user_id_fkey user_logs_user_id_fkey 4 u.id 208 Using where SQL view: SELECT DISTINCT `u`.`id` AS `id`, `u`.`username` AS `username`, `u`.`last_activity` AS `last_activity`, `u`.`last_item` AS `last_item`, `u`.`last_article` AS `last_article`, (SELECT Count(0) FROM `user_logs` `l` WHERE ( ( `l`.`user_id` = `u`.`id` ) AND ( `l`.`date_of` >= ( Curdate() - INTERVAL 6 month ) ) )) AS `access_count` FROM (`user` `u` JOIN `comment` `c` ON(( ( `u`.`id` = `c`.`user_id` ) AND ( `c`.`date` >= ( Curdate() - INTERVAL 2 month ) ) ))) WHERE ( ( ( `u`.`last_item` >= ( Curdate() - INTERVAL 2 month ) ) OR ( `u`.`last_article` >= ( Curdate() - INTERVAL 2 month ) ) OR ( `c`.`date` >= ( Curdate() - INTERVAL 2 month ) ) ) AND ( NOT(( `u`.`username` LIKE '%Smaza' )) ) ) ORDER BY `u`.`id` |
||
Alphard Profil |
Nejkritičtější se mi zdá ten poddotaz počítající
access_count spolu s distinct . Když zkusíte dotaz provést bez výpočtu access_count , zrychlí se to?
Zkusil bych verzi select u.id, u.vsechny_sloupce from users u left join (select user_id from comment where `date` >= ( Curdate() - INTERVAL 2 month ) group by user_id) t on u.id = t.user_id where podminky na tabulku u OR t.user_id is not null order by u.id 22:30 oprava, z join jsem udělal left join a připsal jednu podmínku. Nevšiml jsem si, že je tam OR a ne AND. |
||
Kajman Profil |
#3 · Zasláno: 1. 6. 2015, 22:55:35
Navíc: pokud je vnitřní join na tabulku comment, tak tam budou vždy jen řádky uživatelů, kteří komentář za poslední dva měsíce měli. Podmínky na last_item a last_article bez left joinu postrádají smysl.
V tabulce comment bych udělal dvousloupcový index (user_id, date). Nebo vytvořil v tabulce uživatelů obdobný sloupec last_comment nebo všepostihující last_anything. V tabulce user by se mohly hodit indexy nad last_ sloupci. V tabulce user_logs bych udělal dvousloupcový index (user_id, date_of). Další zrychlení by mohlo být ve chvíli, kdyby to nebylo view, ale přímý dotaz, kde misto curdate() bude skutečné datum dosazené aplikací - mysql pak může používat interní cache pro další dotazy. |
||
abc Profil |
Díky za odpovědi a funkční řešení.
Alphard: „Nejkritičtější se mi zdá ten poddotaz počítající access_count spolu s distinct. Když zkusíte dotaz provést bez výpočtu access_count, zrychlí se to?“ Neměřitelně „Zkusil bych verzi“ Toto funguje, pouze je potřeba z toho subselectu vytvořit ještě jedno view, protože „The SELECT statement cannot contain a subquery in the FROM clause.“ Docela by mě zajímalo, jaktože je toto řešení rychlejší. Nemohl byste to prosím někdo zdůvodnit? Kajman: „Navíc: pokud je vnitřní join na tabulku comment, tak tam budou vždy jen řádky uživatelů, kteří komentář za poslední dva měsíce měli. Podmínky na last_item a last_article bez left joinu postrádají smysl.“ O to mi jde - last_item a last_article jsou úplně jiné věci. Kdyby to bylo pomalé v budoucnu, zkusil bych ty indexy, zatím tam nějaké jsou, tak zatím další přidávat nebudu. |
||
Alphard Profil |
#5 · Zasláno: 2. 6. 2015, 21:25:26
Ten váš dotaz prvně spojí user a comment (zbytečně vzniká velká sada dat, viz dále), pak se dočasná sada omezí dle podmínek where a začnou se vyhodnocovat jednotlivé sloupce (výpočet
access_count pro každý záznam). Po vyhodnocení sloupců přijde to nejhorší, distinct v této podobě znamená groupování podle velkého množství sloupců + toho vypočteného, tj. nelze použít indexy.
Můj dotaz obchází ten hlavní problém (zbytečně se joinuje, aby se následně draze seskupovalo) tím, že k tabulce users připojí již groupovanou tabulku sestavenou z comment. Zdůrazňuji dvě věci: 1. tady se může groupovat podle indexu a 2. ta vazba je 1:1, nedojde k rozšíření datové sady. Ušetří se tvorba dočasných tabulek. „O to mi jde - last_item a last_article jsou úplně jiné věci.“ Nechápete. Ta podmínka je tam zbytečná, protože záznamy tuto podmínku nesplňující se do té sady nikdy nedostanou. V tomhle ohledu se můj dotaz nechová ekvivalentně tomu vašemu, ale myslím, že se chová tak, jak jste to chtěl :-) |
||
Časová prodleva: 9 let
|
0