MySQL: Brisanje pomoću Left Join-a

Danas sam ponovo morao da se pozabavim jednom ogromnom tabelom i uklonim sve podatke iz nje koji nisu imali odgovajuće reference u drugoj tabeli, idealan podsetnik koliko su podupiti u MySQL-u sporiji od Joinova 🙂

Da malo objasnim situaciju, imam skript koji između ostalog generiše tzv. “typo” domene, tako da imam jednu master_domains tabelu sa originalnim domenima i result_domains sa generisanim tipo domenima. Nešto poput ovoga:

mysql> describe master_domains;
+--------+------------------+------+-----+---------+----------------+
| Field  | Type             | Null | Key | Default | Extra          |
+--------+------------------+------+-----+---------+----------------+
| id     | int(10) unsigned | NO   | PRI | NULL    | auto_increment | 
| domain | varchar(255)     | NO   | UNI | NULL    |                | 
+--------+------------------+------+-----+---------+----------------+
2 rows in set (0.07 sec)

mysql> describe result_domains;
+-----------+------------------+------+-----+---------+----------------+
| Field     | Type             | Null | Key | Default | Extra          |
+-----------+------------------+------+-----+---------+----------------+
| id        | int(10) unsigned | NO   | PRI | NULL    | auto_increment | 
| domain    | varchar(255)     | NO   | UNI | NULL    |                | 
| master_id | int(10) unsigned | YES  | MUL | NULL    |                | 
+-----------+------------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

Tabela result_domains ima polje master_id koje je spolji ključ ka id polju u master_domains tabeli. E sad, obzirom da pored ovoga takođe imam domene koji se na razne druge načine generišu (komplikovano za objasniti), danas sam imao zadatak da između ostalog počistim sve domene iz master_domains tabele koji nemaju odgovarajući ključ (master_id) u result_domains tabeli.

Pomoću pod upita ovo se može postići jednostavnim kverijem poput ovoga:

delete from master_domains where id not in 
(select master_id from result_domains_frontend)

Obzirom da se držim pravila da pre svakog brisanja odradim i select kveri sa istim parametrima u where klauzi, došli smo do ovog select kverija:

select * from master_domains where id not in 
(select master_id from result_domains_frontend) limit 10

Međutim on se izvršavao toliko dugo da sam nakon nekoliko minuta rešio da ga prekinem. Pouzdano znam da su podupiti mnogo sporiji od join-ova (iako su daleko elegantniji za pisanje), tako da sam rešio da isti kveri napišem jednim left joinom.

Left Join je savršeno oruđe kada želite da nađete one podatke iz prve (leva) tabele koji ne postoje u drugoj tabeli. Oni takođe imaju izvesne prednosti u odnosu na podupite obzirom da se izvršavaju znatno brže a uz to su i kompatibilni sa starijim verzijama MySQL-a koje podupite ne podržavaju (MySQL < 5.x). Međutim delete sintaksa je malo drugačija tako da sam nakon par pokušaja i listanja manuala došao do sledećeg ekvivalenta:

delete master_domains.* from master_domains 
left join result_domains_frontend 
on master_domains.id=result_domains_frontend.master_id 
where result_domains_frontend.master_id is null ;

I nakon par desetina sekundi došlo se do konačnog rezultata:

mysql> delete master_domains.* from master_domains 
left join result_domains_frontend 
on master_domains.id=result_domains_frontend.master_id 
where result_domains_frontend.master_id is null ;
Query OK, 270558 rows affected (46.58 sec)
mysql> 

2 thoughts to “MySQL: Brisanje pomoću Left Join-a”

Leave a Reply

Your email address will not be published. Required fields are marked *