Autor Zpráva
Honza56
Profil *
Dobrý den,
mám tabulku s účty na fóru a sem tam nějaký smažu v databázi z určitého důvodu, ale na fóru po tomto uživateli zůstane spousty dalších informací v dalších tabulkách. A já potřebuji tyto informace průběžně mazat (pomocí CRON)

Momentálně jsem SQL pro vymazání dalších informací sepsal takto (je jich více, pro příklad uvádím pouze 3) (momentálně je to linux script, ale nejspíše to přepíšu do PHP):
DELETE FROM forum_attachments WHERE poster_id NOT IN (SELECT user_id FROM forum_users);
DELETE FROM forum_banlist WHERE ban_userid NOT IN (SELECT user_id FROM forum_users);
DELETE FROM forum_bookmarks WHERE user_id NOT IN (SELECT user_id FROM forum_users);


Ovšem toto je velmi nepraktické, pokud na fóru máte již 10 000 uživatelů+ (zbytečně se při každém dotazu projíždím 10 000 uživatelských ID). Proto bych tyto ID potřeboval vybrat pomocí jednoho SQL dotazu a poté je uložit do nějakého použitelného pole, abych tuto proměnnou mohl použít v SQL dotazech, tzn. například:
DELETE FROM forum_attachments WHERE poster_id NOT IN ($user_ids);
DELETE FROM forum_banlist WHERE ban_userid NOT IN ($user_ids);
Kajman_
Profil *
A jak dlouho zmíněné dotazy trvají? Myslím, že budou rychlejší než ty, kterých chcete dosáhnout.
Honza56
Profil *
Kajman:
Jak dlouho Vám přesněji neřeknu, jelikož CRON script je nastaven asi na 4:00 ráno, ovšem zcela logicky musí být pomalejší, když budu 15x tahat všech ID uživatelů fóra (SELECT user_id FROM forum_users), když to můžu udělat pouze jednou a uložit daná data do nějakého pole (sice bude objemné, ovšem nevím, zda to ve výsledku nebude rychlejší), a poté s tím dále pracovat, nebo se pletu? Děkuji předem
Kajman_
Profil *
Tipnul bych, že bude rychlejší to současné. Dotaz si můžete samozřejmě spustit mimo cron, ať zjistíte, jak dlouho trvá.
Honza56
Profil *
Kajman:
Skript jsem si zkoušel pouštět mimo CRON a po +-10min jsem se nedočkal výsledku a jelikož provozuji server, který musí být online a bez vytížení (tento skript vždy vytíží MySQL), tak jsem si více nemohl dovolit, tak jsem přemýšel, že by toto mohlo být kratší.

Teď mne napadá, že bych si to mohl vyzkoušet například pouze u jedné tabulky, a porovnat čas.

Ovšem nejsem si jist, jak uživatelská ID uložit do nějakého pole, aby byly ve stylu 1,3,4,5,10, aby pak SQL dotaz vypadal:
DELETE FROM forum_banlist WHERE ban_userid NOT IN (1,3,4,5,10);


Děkuji
Kajman_
Profil *
Tak to je opravdu pomalé, to skoro vypadá, kdyby se ta závorka vykonávala pro každý řádek zvlášť (což semtam mysql opravdu dělá, ale pravidlo pro to jsem nepochytil). Zkusil bych ještě toto
DELETE FROM x using forum_attachments x left join forum_users u on x.poster_id=u. user_id  WHERE x.poster_id is null;

mohlo by to být rychlejší a snad to nemaže nic, co nemá :-)
Kajman_
Profil *
bez mezery mezi u. a user_id
Kajman_
Profil *
A je jasné, že s indexem na poster_id bude dotaz svižnější.
Honza56
Profil *
Kajman:
Tento dotaz jsem zkusil, ale ovšem nic nemaže. Když smažu dané uživatele z tabulky forum_users a spustím tento SQL dotaz, pak stejně po uživatelích s tímto ID zůstanou záznamy v tabulce forum_attachments.
Nox
Profil
Nejelegantnější by bylo mít databázi podporující cizí klíče a navází akcí na změnu (teď nevím, jak se to jmenuje), např. InnoDB ... tam by se toto chování nastavilo přímo do databáze a o správu by nebylo potřeba se starat

Zkuste tedy něco jako
$ids = "";
$existingIDs = mysql_query("SELECT user_id FROM forum_users");
for($i = 0;$i < mysql_num_rows($existingIDs);$i++) // for jsem takto vlastně ještě nepoužil :)
  $ids .= mysql_result($existingIDs, $i).","; // nebo možná 0 místo $i, teď nevim
$ids = substr($ids, 0, -1);

mysql_query("DELETE FROM forum_attachments WHERE poster_id NOT IN ($ids)");
mysql_query("DELETE FROM forum_banlist WHERE ban_userid NOT IN ($ids)");
mysql_query("DELETE FROM forum_bookmarks WHERE user_id NOT IN ($ids)");
Honza56
Profil *
Nox:
Nejspíše myslíš triggery, ale ty jdou pouze u InnoDB ne? A jelikož nemám všechny tabulky InnoDB (nehodí se to), pak tato možnost nejspíše odpadá.

Jinak tvé řešení se mi zdá také dobré, ale ještě si kdyžtak počkám na reakci Kajmana, nejsem si totiž jist, jak to s tím svým SQL dotazem myslel, jelikož vypadá docela slibně :-).
TomášK
Profil
Nox pravděpodobně myslel
ON UPDATE CASCADE, ON DELETE CASCADE
apod., které jsou jen v InnoDB. Triggery myslím fungují i v MyISAM.

Očekával bych, že přístup řešení přes id je zbytečný, že se v databázi použije cachování, ale nevím o tom tolik, abych se na to spolehnul. Docela by mě to zajímalo, pokud by to někdo věděl.

Myslím, že Kajmanovo řešení možná mělo být takto:
DELETE FROM x using forum_attachments x left join forum_users u on x.poster_id=u. user_id  WHERE u.user_id is null;
Honza56
Profil *
TomášK:
S triggery právě nemám moc zkušenost a možná je to i lepší, ale pro mne je jednodušší 1x za den pustit tento "čistící" skript, než nastavovat všude tyto triggery, když jim ještě navíc moc nerozumím.

Jinak děkuji za opravu toho SQL, vůbec jsem si toho nevšiml :).
No abych pravdu řekl, nevím jestli je nějaký velký rozdíl mezi původním SQL dotazem a tím SQL dotazem, který sepsal Kajman, co se týče rychlosti.

Momentálně to nemám jak vyzkoušet v ostrém provozu, jelikož mám momentálně problémy se serverem, ale zítra zkusím všechny SQLka přepsat podle tvého řešení a uvidíme, zda to pojede rychleji. Děkuji
Nox
Profil
Honza56:
Zopakuji po TomášK - nejsou to triggery :) Jde o akce navázané na cizí klíče, tzn. když smažeš záznam, na který obsahuje sekundární klíč pro jiné tabulky, tak můžeš pomazat i (vybrané) související záznamy ... takže např. pokud smažeš v tabulce uživatelů uživatele, smažou se automaticky i všechny jeho přílohy, nastavení atd.

Anebo se jim nastaví do klíče NULL nebo ti smazání nepovolí atd.

http://cs.wikipedia.org/wiki/Cizí_klíč

TomášK:
Myslim že MySQL je občas podivné, docela bych chápal že v nějakém případě prostě nebude cachovat a asi to tak fakt je... víc jak 10minut je fakt hodně
Kajman_
Profil *
Pardon, byla tam chyba... edit: a koukám, že ji Tomáš už opravil
DELETE FROM x using forum_attachments x left join forum_users u on x.poster_id=u.user_id  WHERE u.user_id is null;


Prostě ty, co s nepovedou prolinkovat s uživatelem.
Honza56
Profil *
Dobré odpoledne. Omlouvám se, že píšu po delší době, ovšem narazil jsem na problém.

Pokud chci smazat záznamy z databáze1 v závislosti na databázi2.

Zkusil jsem použít tento SQL dotaz:
DELETE FROM x using `www`.`account` x left join `forum`.`forum_users` u on x.id=u.id WHERE u.id is null;


ovšem vypisuje chybu:
Unknown table 'x' in MULTI DELETE


Děkuji předem za kladnou odpověď.
Kajman_
Profil *
DELETE FROM `www`.x using `www`.`account` x left join `forum`.`forum_users` u on x.id=u.id WHERE u.id is null;

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