MySQL 5.x – Konačno unapređen klijent

Listajući svoje omiljene WebDev feed-ove, za oko mi je zapao jedan post na sjajnom MySQL Perfomance Blogu:

…if you press CTRL-C MySQL Command Line Client will not exit but will terminate query being executed.

Drugim rečima, u dosadašnjim verzijama MySQL klijenta, kada bi ste ukucali neki query i pritiskom na CTRL-C pokušali da prekinete njegovo izvršavanje, CTRL-C bi zapravo ubio MySQL klijent, ali query nastavlja da se izvršava u pozadini! Rešenje u takvim slučajevima je traženje id-a tog query-a na listi procesa upitom “show full processlist”, a zatim njegovo “ubijanje” upitom “kill 12345” gde je 12345 u ovom slučaju id procesa koji želimo da ubijemo. Dakle, recimo nešto ovako:

mysql> select * from odm_result_keywords where keyword like '%foo%joe%';
^CAborted
bash-2.05b$ mysql -A --enable-local-infile -udinke -ppass mydb
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1512 to server version: 4.1.18-log

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> show full processlist;
+------+-------+----------------------------+-------------------+---------+------+--------------+--------------------------------------------------------------------+
| Id   | User  | Host                       | db                | Command | Time | State        | Info                                                               |
+------+-------+----------------------------+-------------------+---------+------+--------------+--------------------------------------------------------------------+
| 1486 | dinke | localhost                  | mydb | Query   |    3 | Sending data | select * from odm_result_keywords where keyword like '%foo%joe.cl' |
+------+-------+----------------------------+-------------------+---------+------+--------------+--------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> kill 1486;
mysql>

Zahvaljujući izmenama u MySQL klijentu, sada je dovoljno da stisnete CTRL-C, i query će biti odmah prekinut:

mysql> select domain from odm_result_keywords_de where whois_status is null and domain like '%.%.%';
Query aborted by Ctrl+C
ERROR 1317 (70100): Query execution was interrupted
mysql>

Više informacija o ovoj, kao i drugim izmenama u pomenutoj verziji (5.0.25) možete naći ovde.

MySQL – Backup velikih MyISAM tabela

Ako ste ikada morali da backup-ujete ili prebacujete podatke iz jedne ili više MySQL tabela, znate da se za to koristi mysqldump utility, pomoću kojeg jednostavno podatke iz MySQL-a “dumpujete” u neki mojetabele.sql fajl, koji zatim možete sačuvati kao backup, prebaciti i importovati na neki drugi MySQL server, itd. Ovu proceduru koristio sam milion puta do sada, i ona se generalno svodi na izvršavanje sledećih komandi u linuxu:

export:

mysqldump -udinke -pmojpass -hhostname.prvog.servera ime_baze tabela1 tabela 2 tabelan > dump_fajl.sql

import:

mysql -udinke -pmojpass -hhostname.drugog.servera ime_baze < dump_fajl.sql

Tu i tamo pojavi se problem kada prebacujete dump sa novije verzije MySQL-a na stariju, i tada je poželjno specifirati i odgovarajući compability flag prilikom izvršavanja mysqldump komande (--compatible=name gde name može biti mysql323, mysql40, postgresql, oracle itd.).

Elem, pre nekoliko dana zbog prebacivanja MySQL servera sa jedne lokacije na drugu, morao sam da odradim dump solidno velikih MySQL tabela (10-tak tabela gde je svaka imala preko 2 miliona slogova). Nakon užasavajuće duge procedure dumpa, gzipovanja i scpovanja na drugi server, konačno sam startovao import. Međutim, nakon 3 sata (tri sata) umesto standardne "no news is a good news" poruke, kada sam bacio pogled na status dočekala me je sledeća poruka ...:

[dinke@um-917 ~/public_html]$ mysql -udinke -p325ewfwt23rasf
keyword_discovery < es_miner_data.sql
ERROR 1582 (23000) at line 163833: Duplicate entry '1167548' for key
'PRIMARY'

WTF? Prebacivao sam podatke sa starije verzije na noviju, što znali da import mora proći glatko! Ovo bi trebalo da znači da je MySQL negde nešto pobrljavio sa indexima, i umesto da čekam još 2 sata da se odradi check & repair, odlučujem se da napravim ponovo dump fajl, ovaj put sa ignore opcijom, kako bi svi inserti u dump fajlu bili "insert ignore" tako da u slučaju ovakve greške ne bi došlo do pucanja. Ne preterano pametno, ali podaci nisu extremno osetljivi i mogu da dozvolim luksuz da izgubim desetak slogova, ali ne i desetak sati za import!

Naravno, novi dump, zip, scp ... to je traajalooo ... toliko dugo da sam posle par sati nakon startovanja importa krenuo da mozgam sa administratorom (kuki) oko alternativnih rešenja. A rešenje je bilo jednostavno ali efikasno. Prekopirali smo sve MySQL data fajlove sa jednog servera na drugi (*.MYI, *.MYD i *.frm fajlove), a zatim odradili myisamchk kako bi sredili pomenute tabele, jer nismo smeli da spuštamo server prilikom backup-a što generalno može da prouzrokuje dosta problema (tipa oštećene tabele) ako se na ovaj način backupuju fajlovi.

Sve u svemu, ova operacija prošla je jako brzo (najduže je trajalo kopiranje fajlova sa jednog hosta na drugi), i za manje od pola sata cela procedura bila je završena.

Zaključak do koga smo došli je da je kod velikih tabela zbog dužine trajanja operacije dumpovanje praktično neprihvatljivo kao backup rešenje, i da se samim tim kao jedino rešenje nameće kopiranje MySQL data fajlova. Kod MyISAM tabela to nije nikakav problem, jer su one "platform safe", tj. binarni fajl kreiran na jednoj platformi (recimo *.MYI fajl na linuxu) radiće bez ikakvih problema na drugoj platformi (recimo isti *.MYI fajl na Windowsu).

Client size resizovanje slika

Radeći na servisu Blogodak, nedavno sam se susreo sa problemom kod slika velikih dimenzija koje neki korisnici uključuju u svojim feedovima. Naime, kako Blogodak “vuče” feed-ove sa raznih domaćih blogova, a sa njima i slike koje se u njima nalaze, dešavalo se da one dimenzija većih od 560px uredno “skrljaju” layout blogotka, obzirom da to e == “Microsoft Internet Explorer”)
{prevazilazi predviđenu veličinu containera, tako da u najboljem slučaju dolazi do pojave horizonatalnog skrol bara. Kako nemamo nikakav uticaj na slike koje se vuku sa servera gde su hostovane, server side varijante(npr. resize korišćenjem GD liba ili Image Magicka) nisu primenjive, jedino rešenje je da se dimenzije slike smanje direktno u browseru – Client Side.

CSS Rešenje
Za browsere koji imaju potpunu podršku za css2, dovoljno je staviti nešto tipa:

.container img{
  max-width:560px;
}

u stil strane, tako da će sve slike koje se nalaze unutar nekog <div idclass=”container”>…</div> elementa biti ograničene na max 560 piksela, tj. biće automatski resizovane na odgovarajuću veličinu. Naravno, ovo ne radi u IE-u (verzije < 7) tako da je potreban hack 🙂 IE Hack (CSS verzija)

.container img{
  max-width:560px;
  /*hack for IE*/
  width: expression(this.width > 560 ? 560: true);
}

Ovaj css hack je validan samo u IE-u, koristi se neka vrsta “ternarnog operatora”, a sam hack skinut je sa ovog bloga. Rado bih vam rekao da više informacija potražite tamo, ali i sam autor priznaje da na razume mnogo oko toga “kako to radi”, ali jednostavno radi. Za ljubitelje standardnijih rešenja, sledi JS verzija.

IE Hack (JS verzija)

Obzirom da mi se nije svidela ideja da koristim nevalidan css kod koji uz to i ne razumem u potpunosti(na stranu što je pravio i neke nekoegzistentne probleme sa IE-om za koji je i namenjen), odlučio sam se za JavaScript rešenje koje sledi.

function fixImages()
{
  //fix images for ie only
  if(navigator.appName == "Microsoft Internet Explorer")
  {
    for(i=0; i<document.images.length; i++)
    {
      //if image is bigger than 560
      if(document.images[i].width > 560)
      {
        imgRatio = document.images[i].width/document.images[i].height;
        document.images[i].width = 560;
        document.images[i].height = 560 / imgRatio;

        //hack neophodan da bi se uklonio skroler zbog prvobitne velicine slike
        //mainContent je ime div kontejnera koji drzi sadrzaj strane				
        divid = document.getElementById('mainContent');
        content = divid.innerHTML;
        divid.innerHTML = '';
        divid.innerHTML = content;
      }
    }
  }
}

Ova funkcija se poziva nakon učitavanja stane(onLoad). U slučaju da je u pitanju IE, proveravaju se dimenzije svih slika na strani(parsuje se niz document.images), i u slučaju da dimenzije prevazilaze 560 piksela, setuju se na manje, uz očuvanje proporcija slike. Naravno, ovaj metod ima manu, jer je neophodno da se sve slike prvo učitaju, pa tek onda dolazi do resizovanja. Kod IE-a i pored resizovanja slike na “prihvatljive” dimenzije, bilo je potrebno nekako mu i staviti do znanja da je došlo do promene dimenzija(samo resizovanje nije dovoljno da nestane horizontalni skroler), tako da je bilo neophodno ručno ili skriptabilno rezisovati i prozor browsera. Srećom posle manjeg “prčkanja” sa alternativama prošlo je i jednostavnije rešenje sa setovanjem kontejnera cele strane na prazan string i vraćanjem na prvobitno stanje korišćenjem innerHTML-a.

Nadam se da će ovo nekome biti od koristi 🙂