Optimizari la lucrul cu bazele de date – incarcarea predictiva

databaseAm mai scris despre baze de date intr-un articol anterior (database sharding) si probabil voi continua sa mai ating si alte subiecte legate de baze de date in perioada urmatoare.

De multe ori avem de-a face cu aplicatii care genereaza multe requesturi catre baza de date, unde fiecare request inseamna un consum mic de resurse dar toate, adunate, inseamna mult, mai ales cand se executa in cascada, pe un singur fir de executie.
In alte cazuri avem de-a face cu sql-uri destul de complexe care nu mai pot fi optimizate si pur si simplu trebuie sa asteptam ca ele sa se execute.

De fiecare data cand avem de-a face cu timpi de incarcare mari din cauza unor sql-uri care dureaza mult, indiferent daca este vorba de unul sau mai multe care se executa, se genereaza un disconfort pentru utilizator si acest disconfort niciodata nu se traduce in ceva bun pentru noi :) .

In articolul de fata va propun o solutie care poate rezolva doua tipuri de probleme, atat optimizarea lucrului cu baza de date la nivel de request cat si la nivel de aplicatie. Am incercat sa gasesc referinte catre o astfel de procedura si n-am gasit mare lucru dar cred ca cel mai bun nume ar fi “Predictive database loading“.

Ce inseamna Predictive database loading

Consideram urmatorul curs de evenimente A -> B -> C -> D. Putem considera ca daca evenimentele A si B apar atunci avem o probabilitate foarte mare sa se ajunga si la evenimentul D.
Un exemplu din real life: daca am o felie de paine pe care am o felie de rosie am urmatoarea succesiune de evenimente posibile: (A) daca intorc felia cu fata in jos -> (B) felia de rosie se va desprinde de felia de paine -> (C) felia de rosie va cadea pe jos -> (D) ma voi duce sa iau alta felie de rosie . Daca am “observat” ca evenimentele A si B s-au petrecut cu siguranta vom avea si evenimentele C si D deci ne putem pregati pentru acestea.

Predictive database loading – la nivel de request

Un request este o cerere a unui utilizator catre aplicatie iar durata de viata a acestui request este de la momentul in care a fost generat prin actiunea utilizatorului pana la momentul in care este servit rezultatul catre acesta.

Sa luam exemplul unui script php. Pe parcursul executiei sale putem avea 1, 2, 5 sau 50 de sql-uri care se executa.
In aceasta situatie stim clar ca daca a inceput executia primului sql atunci toate vor fi executate. In cazul acesta predictia este 100% reala

Predictive database loading – la nivel de aplicatie

Sa luam exemplul unei aplicatii financiare. Urmatoarea secventa este posibila: listare furnizori -> selectie furnizor -> listare produse -> selectie produs -> afisare produs -> listare comenzi pentru produsul respectiv.
O astfel de selectie inseamna mai multe requesturi care pot surveni la intervale diferite. La selectia unui furnizor putem considera ca avem o probabilitate de x% ca se va face si o listare de comenzi si, in consecinta, putem face, inca din momentul selectiei un produs, o incarcare si a listei de comenzi.
Este un exemplu simplist dar descrie perfect modul de incarcare predictiva din baza de date.

Cum putem face un sistem de predictii la nivel de aplicatie care sa functioneze?

Este destul de simplu daca privesti problema suficient de abstract.
Fiecare pas facut de un utilizator poate fi salvat, intregul traseu al utilizatorului prin aplicatie poate fi salvat. Toate aceste succesiuni de actiuni, daca devin repetitive, pot deveni pattern-uri de activitate, acele secvente de care aminteam mai sus.

Dupa un timp de utilizare al aplicatiei putem avea deja o colectie de pattern-uri pe care o putem folosi pentru predictiile pe care urmeaza sa le facem. Bineinteles ca putem defini si manual astfel de pattern-uri, daca analizam bine aplicatia.
De acum incolo nu ne mai ramane decat sa identificam pattern-urile de activitate si sa executam predictiv sql-uri.

Observatie: va trebui sa definim la nivel de aplicatie o variabila, sa-i zicem min_pattern_match; aceasta variabila este folosita in momentul in care comparam activitatea curenta a unui utilizator cu pattern-urile definite si vom lua decizia de a executa predictiv un sql numai in momentul in care potrivirea intre activitatea userului si un pattern definit va fi mai mare decat aceasta valoare.

Cum facem incarcarea predictiva, dpdv tehnic?

Simplu, tot ce avem nevoie este memcached.
In momentul in care identificam un pattern lansam in executie in background (alt thread) sql-ul pe care vrem sa-l avem disponibil mai tarziu; dupa executie acesta va scris in memorie iar in momentul in care avem nevoie de recordset-ul respectiv tot ce trebuie sa facem este sa verificam intai daca il avem in memorie si sa-l luam de acolo.

Exemplu practic: stiu ca peste 2 pasi voi avea nevoie sa execut sql-ul “Select * from t_orders where client_id=1″. Lansez in executie acest sql prin metoda descrisa anterior si acesta va fi scris in memorie. Cheia catre recordset-ul rezultat va fi chiar md5(sql).

In ce cazuri avem nevoie de predictive database loading?

  • request-uri cu multe sql-uri: putem lansa in executie inca de la inceput sql-urile care in mod normal s-ar executa la final;
  • magazine online -> listari de produse: avem definit un pattern conform caruia la orice listare de monitoare utilizatorul va merge si pe pagina 2 si 3; inca de pe prima pagina putem lansa in executie sql-urile care returneaza rezultatele pentru paginile 2 si 3.

Exemplele pot continua dar cred ca ati inteles ideea.

Daca aveti propuneri de imbunatatire ale acestui principiu de optimizare al lucrului cu bazele de date astept comentariile voastre.

Daca ti-a placut acest articol citeste si:

  1. Ideea este intr-adevar interesanta si imi pot imagina citeva scenarii in care sa se dovedeasca utila.

    Sunt insa multe aplicatii in care lantul decizional este extrem de complex si din acest motiv aplicarea acestui algoritm poate conduce la pregatirea unui set de date gresit sau pregatirea unui set de date prea mare sau pregatirea unui set de date prea mic. Toate aceste scenarii inseamna consum inutil de resurse (CPU/disk IO/bandwidth). Daca adaugi si alte elemente de complexitate (validitatea datelor pregatite, expirarea datelor pregatite, etc), cred ca din pacate numarul de scenarii in care poate fi aplicata scade destul de mult.

    Optiunea pe care as studia-o eu ar fi posibilitatea executarii acestor operatiuni in paralel, i.e. daca momentul X necesita setul de date A, B, C, D, care dintre aceste sunt independente si pot fi regasite in paralel astfel incit viteza de pregatire a rezultatului sa nu mai fie time(A) + time(B) + time(C) + time(D), ci un max(time(secventa-de-date)…).

    • Daniel Buca
    • October 22nd, 2009

    Numarul de scenarii este limitat de tipul aplicatiilor dezvoltate si de modul in care sunt dezvoltate.

    Bineinteles ca la o aplicatie unde trebuie sa lucrez cu date real time nu pot aplica o astfel de metoda.
    La majoritatea aplicatiilor web, insa, putem stii ce tipuri de date au o dinamica atat de mare incat sa nu putem implementa un sistem predictiv.

    Sistemul de predictive loading la nivel de aplicatie merge foarte bine in situatiile in care avem citire de date si nu neaparat prelucrari.

    Referitor la sugestia ta: bineinteles ca time(A) + time(B) + time(C) + time(D) > max(time(secventa)), exact asta este predictive loading la nivel de request dar uite ce ziceam eu: lansez B, C, D in background (3 threaduri noi) si eu execut normal A si incep sa lucrez cu el si fac output catre cliebt. In momentul in care am terminat cu A sunt gata si B C si D.
    Altfel ar trebui sa astept sa treaca timpul max(time(secventa)), perioada in care aplicatia nu ar face nimic, ar trebui sa astepte.

    Ce parere ai?

  2. Cred ca diferenta majora dintre cele 2 abordari este momentul aplicarii lor. Propunerea mea se refera la regasirea/pregatirea datelor pentru momentul t, pe cind algoritmul descris de tine se refera la regasirea/pregatirea datelor pentru momentul t + 1 (cel putin asta e intelegerea mea). Daca vrei algoritmul meu se refera la paralelizare, pe cind cel propus de tine se refera la predictie + paralelizare.

    Acum ca aplicabilitate: algoritmul propus de mine se potriveste cu orice scenariu care necesita seturi de date multiple semi-independente (fara nici o alta restrictie). Din cite am inteles eu, algoritmul propus de tine poate fi aplicat in scenarii in care la momentul t se stie ca va exista un pas aditional la t + 1 care este sigur/are o probabilitate mare.

    • Daniel Buca
    • October 22nd, 2009

    Da, ai inteles corect.
    Acum recunosc ca pot fi subiectiv dar ma gandesc ca avantajul oferit de sistemul predictiv este faptul ca poate invata singur din activitatea userilor.

    In alta ordine de idei: ambele sisteme pot functiona foarte bine, implementate chiar in aceeasi aplicatie, se pot completa unul pe celalalt. Nu crezi?

data recovery