Autor Zpráva
davchy
Profil
Zdravím,

DELETE FROM `cfp_bandwidth` WHERE `id` NOT IN (SELECT max(`id`) AS `meta_id` FROM (SELECT * FROM `cfp_bandwidth`) AS `t1` GROUP BY `img_id`);

používám tento dotaz, ale protože má `cfp_bandwidth` 7,5M řádků, odstaví to na celý den aplikaci, nebo zkolabuje.
Lze toho stejného dosáhnou podstatně lehčím dotazem, nebo aby dotaz běžel „po částech“? Jde o to, že potřebuji vymazat všechny řádky se stejným `img_id` kromě toho nejmladšího.

Díky
Kajman
Profil
Možná něco takového (bez záruky na data :)
DELETE FROM b1
USING `cfp_bandwidth` b1
       LEFT JOIN (SELECT Max(`id`) AS `meta_id`
                  FROM   `cfp_bandwidth`
                  GROUP  BY `img_id`) AS `b2`
              ON b1.id = b2.meta_id
WHERE  b2.meta_id IS NULL 

Index na img_id případně na kombinaci (img_id, id) bude pro takové mazání vhodný.


Případně může dopadnou rychleji v transakci přesunout chtěné řádky do stejné prázné tabulky, používanou truncnout a vrátit řádky zpět. Případně tabulku dropnout a tu původně práznou přejmenovat.
Kajman
Profil
Ale koukám, že jste stejný dotaz už testovat chtěl. Jak to dopadlo?
davchy
Profil
Bohužel, výsledek je stejný. I po přidání indexu je aplikace po spuštění dotazu nepoužitelná :(
Kajman
Profil
davchy:
Bohužel, výsledek je stejný.

Takže také celý den? Neběží to s tím joinem a indexem třeba jen půl dne?

Když mažete 7 milionu řádků, tak to potrvá. Urychlit by to mohla ta zmíněná pomocná tabulka. Něco jako

CREATE TEMPORARY TABLE mojetmp AS
  SELECT b1.*
  FROM   `cfp_bandwidth` b1
         JOIN (SELECT Max(`id`) AS `meta_id`
               FROM   `cfp_bandwidth`
               GROUP  BY `img_id`) AS `b2`
           ON b1.id = b2.meta_id;
TRUNCATE TABLE cfp_bandwidth;
INSERT INTO cfp_bandwidth SELECT * FROM mojetmp;
DROP TEMPORARY TABLE mojetmp;
davchy
Profil
Zda celý den, to nevím. Pustil jsem ho v okamžik kdy jste ho postnul a stále běží (a blokuje běh aplikace).. ..uvidíme jak to dopadne přesně. Případně bych vyzkoušel ten další postup. Díky
davchy
Profil
Ta druhá varianta je o 50% rychlejší. Navíc prvním během se počet řádků zredukoval na cca 100k a teď už je to otázka maximálně minuty.
Mockrát děkuji.
davchy
Profil
Zdravím, jsem tu opět..

..a opět se jedná o to stejné. Ten poslední dotaz s použitím dočasné tabulky fungoval skvěle, jak jsem i psal, ale narazil jsem na další problém: maže i to, co potřebuji ponechat.

Potřeboval bych, aby řádek ponechal, pokud je v tabulce `img_id` jen jednou. Mazat má pouze pokud se vyskytne více jak jednou a to ty nejstarší, tedy ty, které mají nižší `id`.

Prosím tedy, jak by měl vypadat upravený dotaz? Mockrát děkuji.
Kajman
Profil
Pokud je v tabulce jediný řádek s daným img_id, bude i tak v temporary tabulce a tudíž bude zachován. Máte to uzavřené do transkace, případně zamykáte tabulku, aby ji mezi těmy příkazy nikdo neupravoval?

Ještě můžete zkusit jednu variantu s delete z faq, třeba bude o fous rychlejší než verze v [#2] (ale tipuji, že to bude podobné, možné i pomalejší). Opět jeden index na dvou sloupích (img_id, id).
DELETE FROM t1
USING  cfp_bandwidth t1,
       cfp_bandwidth t2
WHERE  t1.img_id = t2.img_id
       AND t1.id < t2.id

Vaše odpověď

Mohlo by se hodit

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

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