Autor Zpráva
abc
Profil
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
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
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 :-)

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