MySQL Jokeri

Pitanje za milion dolara u nekom popularnom kvizu. Imate samo 15 sekundi za odgovor. Srecni ste jer ste izvukli pitanje iz vase omiljene oblasti :)

Kako obrisati sve korisnike ciji nick pocinje sa donjom crtom (’_').

I vas odgovor je naravno:

delete from users where username like '_%';

Vec mastate o raskalasnom zivotu daleko od kompjutera, mozda i neka jahtica pride (i sve sto ide u to lol). Glas voditelja vraca vas u surovu realnost. “Zao mi je, ovo nije tacan odgovor”. U neverici gledate vas query i milione koji su otisli u nepovrat.

Verovali ili ne, slicnu nevericu iskusio sam na svojoj kozi pre nekoliko veceri, tacnije 8. aprila. U tabeli sa nekoliko miliona generisanih domena uocen je bug (mala greska u regularnom izrazu) i nekako su generisani i domeni koji pocinju sa znakom “_”. Underscore (donja crta) naravno nije dozvoljen kod domena, bug je ispravljen ali treba obrisati i te nevalidne domene iz baze. Nista lakse, jedan brzi query i sve ce ubrzo biti pocisceno. Otvaram mysql klijent i bez mnogo razmisljanja kucam:

mysql> delete from result_domains where domain like '_%';
Query OK, 9035782 rows affected (9 min 57.35 sec)

WTF!?? Query je obrisao sve domene iz tabele. Ali kaaakooo???

I onda se setim. Donja crta - ‘_’ je poput ‘%’, takodje joker karakter koji za razliku od ‘%’ (koji menja ‘nula ili vise’ karaktera), ‘_’ menja tacno jedan karakter. Ne secam se kada sam ga poslednji put koristio (ako sam ga uopste koristio), ali znam da mi je on dosao glave.

Cimam admina na ICQ … treba mi backup, server taj i taj, tabela ta i ta, poslednji koji imamo … ASAP! Posle 30-tak sekundi admin se javlja “ok, poslednji koji imamo je od 8 marta. Gde da ti stavim?”. FUCK!!!

FUCK!!! FUCK!!! FUCK!!! FUUUUCK!!!

Ustajem od kompjutera i besno setam kroz sobu. Na postoji nacin da objasnim klijentu da sam jednim jedinim kverijem sjebao sate i sate mukotrpnog rada, podatke vredne verovatno hiljade dolara. Da imam utoku verovatno bih pao u iskusenje da pucam sebi u glavu. Mozda pre toga da sredim i admina? Kako god, sta je tu je, ne preostaje nista drugo nego da napisem email i objasnim svom klijentu sta se desilo.

Sedam ponovo za comp, ali umesto da otvorim thunderbird, cimam ponovo admina.

- Ja: “Jebote … kako se desilo da je poslednji backup star mesec dana???”
- Admin: “Kako to mislis? Ovo je backup od sinoc!?”
- Ja: “Rekao si 8 mart???”
- Admin: “Ups. Sorry, 8. April. Sad gledam, kreiran je pre samo par sati. Moze?”

I tako, my ass has been saved. Ali moglo je i biti drugacije. Mnogo drugacije.

Pouka price:

1) Budite ekstremno oprezni kada kucate nesto unutar mysql klijenta (ili phpmyadmina) koji barata sa live podacima
2) Ako morate da brisete/update-ujete nesto, uvek uradite prvo count nad istim podacima i istom where klauzom kako bi ste se uverili da je to bas ono sto ste zeleli.

Npr:

mysql> select count(*) from result_domains where domain like '_%';
+----------+
| count(*) |
+----------+
|  9035782 |
+----------+
1 row in set (5.27 sec)

(ups nesto ne valja, ovo ce obrisati sve domene koje imamo)

mysql> select count(*) from result_domains where domain like '\_%';
+----------+
| count(*) |
+----------+
|        0 |
+----------+
1 row in set (4.18 sec)

Aha, sada je sve ok :)

3) Uvek pravite redovan backup. Ako to za vas rade admini postarajte se da rade svoj posao kako treba. Cak i tada nije losa ideja da s vremena na vreme napravite sopstveni backup.

P.S. Problem sa pocetka price (matchovanje stringa koji pocinje sa ‘_’) resava se jednostavnim escapovanjem specijalnog karaktera. Dakle:

select foo from footable where somefield like '\_%';

ili ako ste ljubitelj regularnih izraza:

select foo from footable where somefield regexp '^_';

Comments

  1. kuki
    April 11th, 2008 | 16:53

    Sva sreća da je admin ipak radio svoj posao ;)

  2. April 11th, 2008 | 16:59

    da da :)

  3. April 11th, 2008 | 18:12

    Hehe. :)

  4. April 11th, 2008 | 18:27

    Bekap uvek i obavezno, a na brzaka moze i ovakav “bekap”: http://blog.zemoon.com/simple-mysql-table-backup-restore/

  5. April 11th, 2008 | 18:31

    He, he, ala te je iscimao. :)

    Ma ništa gore od tog prčkanja na živo i kad nakon pritiska na Enter shvatiš da si zadao pogrešan WHERE uslov, ili ga nisi zadao uopšte a trebalo je… O:)

  6. April 11th, 2008 | 20:20

    LOL…. odličan tekst…

  7. April 12th, 2008 | 8:17

    Uvek backup cele baze pre igranja, posebno ako se nešto briše. Uvek to sebi kažem, nikada ga ne napravim i s vremena na vreme obrišem stvari koje ne bi trebalo da obrišem :)

    Nego, zašto ti ovom count() treba 5 sekundi??? Kačiš se na remote server ili?

  8. April 12th, 2008 | 10:54

    @Ilija
    Nije ti palo na pamet da je to zato sto ima 9 miliona slogova :) ? Ok, delom je i zbog hardware-a posto je u pitanju single CPU masina :)

  9. April 13th, 2008 | 8:48

    Ovo ide uz temu (cisto nek se nadje…):

    function mysql_escape($string, $useInLike = false) {
    if (version_compare(phpversion(), “4.3.0″) == “-1″) {
    $string = mysql_escape_string((string)$string);
    } else {
    $string = mysql_real_escape_string((string)$string, $GLOBALS[’db_link’]);
    }
    if ( $useInLike ) $string = addcslashes($string, ‘%_’);
    return $string;
    }

    :-)

  10. April 13th, 2008 | 12:34

    Препоручујем да све то обављаш у оквиру трансакција, и онда немаш никаквих проблема — ако ти каже да си обрисао сувише редова, знаш да брже боље урадиш ROLLBACK ;)

  11. April 13th, 2008 | 12:38

    А успут, не верујем да вишепроцесорска машина може помоћи у извршавању једног таквог упита који је по својој природи „атомски“.

  12. April 13th, 2008 | 13:26

    U pitanju je bila (default) MyISAM tabela koja koliko znam nema podrsku za transakcije.

  13. April 17th, 2008 | 3:00

    Eehehehe nisi jedini, koji se opekao sa tim jokerima…
    A reci mi sto ne koristis InnoDB engine? Btw. da li si razmislio o kombinaciji MyISAM engina (za SELECT) i InnoDB engina (za INSERT, UPDATE i DELETE? Podatke upisujes u InnoDB tabele, potom ih kopiras u (kompresovanu) MyISAM tabelu… Zahtjeva vise administrativnog posla, ali mislim da bi se isplatilo za tu kolicinu podataka…

Leave a reply