Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Ręczne zapytania MySQL czy AdoDB?
Forum PHP.pl > Forum > Bazy danych > MySQL
Apocalyptiq
Odkąd tylko pracuje z MySQL, używam biblioteki AdoDB - do obsługi baz danych. Chciałem zapytać profesjonalistów, co bardziej się opłaca - wykonywać zapytania ręcznie poprzez fetch, czy używać jakiejś biblioteki do baz danych? AdoDB posiada takie funkcje jak GetOne - pobranie jednego rekordu do zmiennej, GetCol - pobranie kolumny, GetRow - pobranie wiersza itp.
Proszę o wasze opinie, co jest wydajniejsze, co jest poprawniejsze i co wygodniejsze w użyciu smile.gif Po prostu jak radzicie pracować z bazami MySQL smile.gif
(ta biblioteka AdoDB ma około 2MB)

Zrobiłem małe testy czasowe AdoDB i ręcznych zapytań, i ręczne wypadają ok. 3x szybciej smile.gif Tylko że przy AdoDB piszę się mniej kodu, wygodniej nieco się pracuje z bazami. Tylko stosując ręczne zapytania, trzebaby się wyposażyć w jakąś funkcję zabezpieczającą zmienne wprowadzane do zapytań SQL z zewnątrz przed SQL Injection - tj. dodawanie apostrofów w odpowiednich miejscach itp.
nospor
Cytat
Zrobiłem małe testy czasowe AdoDB i ręcznych zapytań, i ręczne wypadają ok. 3x szybciej
Az mnie zaciekawiles: moglbys pokazac jaki kod uzyles do testow?

ps: ja uzywam PDO i nie wyobrazam sobie teraz zabawy w reczne rezanie poprzez mysql_query
Apocalyptiq
Test AdoDB:
Kod
<? function podajCzas(){
        list($usec, $sec) = explode(" ", microtime());
        return ((float)$usec + (float)$sec);
    }
    $start=podajCzas();
    require_once 'inc/db.php';
    foreach($db->GetAll('SELECT * FROM events') as $player){
    print_r($player);}
    echo '
    czas: '.round(podajCzas()-$start,3).' sekund';
    ?>

Test fetch:
Kod
<? function podajCzas(){
        list($usec, $sec) = explode(" ", microtime());
        return ((float)$usec + (float)$sec);
    }
    $start=podajCzas();
    $sql_conn=mysql_connect('localhost', 'root', '***');
    mysql_select_db('siatka');
    $players=mysql_query('SELECT * FROM players');
    while($player=mysql_fetch_assoc($players)){
    print_r($player)];
    }
    echo '
    czas: '.round(podajCzas()-$start,3).' sekund';
    ?>

Wyświetlałem sobie struktury zwracanych tablic i liczyłem czas.
Różnica niby duża, ale uwidoczni się to pewnie przy większych ilościach zapytań na jednej stronie, a na przeciętnych stronach za dużo się ich nie pojawia naraz smile.gif A biblioteki dają większą wygodę pracy z MySQL.

Piszcie swoje opinie na ten temat, co wy używacie do pracy z MySQL, i jak radzicie innym smile.gif
nospor
Twoj test srednio na jeza mi sie podoba.
1) nie sprawdzasz czasu samych zapytan, ale caly czas wlacznie z inicjalizacja klas. Inicjalizacja klas to mala czesc calej aplikacji i jest prawie znikoma w normalnych aplikacjach w porownaniu z caloscia kodu. A u ciebie kodu nie ma prawie wcale
2) Dla adodb podajesz inną tabele niz dla mysql_query(). No chociazby juz tutaj roznice mogą byc duze

Cytat
Piszcie swoje opinie na ten temat, co wy używacie do pracy z MySQL, i jak radzicie innym
Napisalem przeciez: PDO
zzeus
Ja też się od jakiegoś czasu zastanawiam co użyć do komunikacji z bazą danych. Od jakiegoś czasu używam AdoDB, ale poczytałem troszkę o PDO i się zastanawiam czy się nie przesiąść. Za PDO przemawia fakt że jest to moduł wkompilowany w php, więc nie trzeba dołączać niczego do skryptu jak w przypadku AdoDB, no i powinno być szybciej jako że PDO jest skompilowane. Poza tym AdoDB od jakiegoś już czasu chyba nie jest rozwijane. Jednak zrobiłem u siebie na kompie testy i wyniki troszkę mnie zaskoczyły, bo AdoDb okazało się szybsze od PDO ...
Apocalyptiq
nospor - te testy wykonywałem na jednej tabeli, tylko że bawiłem się później na innych tabelach i przez przypadek na forum wkleiłem różne tabele smile.gif
Jak poczytałem nieco o tym PDO, to np. taki kod:
Kod
<?php

    try
    {
       $pdo = new PDO('mysql:host=localhost;dbname=produkty', 'root', 'root');
       $pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      
       $stmt = $pdo -> query('SELECT id, nazwa, opis FROM produkty');
       echo '<ul>';
       foreach($stmt as $row)
       {
           echo '<li>'.$row['nazwa'].': '.$row['opis'].'</li>';
       }
       $stmt -> closeCursor();
       echo '</ul>';
    }
    catch(PDOException $e)
    {
       echo 'Połączenie nie mogło zostać utworzone: ' . $e->getMessage();
    }
?>
Trzeba napisać do wyciągnięcia jednego zapytania. Troche chyba więcej tu kodu niż napisałoby się w takiej sytuacji w AdoDB.
Chciałbym się już na przyszłość ujednolicić co do pracy z MySQL, no i nie wiem... Ręczne zapytania niby wychodzą najszybciej, ale pewnie np. PDO nie napisanoby bez powodu - pewnie jest w czymś lepszy od ręcznych zapytań smile.gif
nospor -> a jak ci się pracuje z PDO? nie ma żadnych kłopotów? bardzo dużo kodu się nie pisze? I jak jest w PDO z zabezpieczeniem przeciwko SQL Injection? W AdoDB wprowadzane zmienne do zapytania SQL wrzucało się najpierw w funkcję Quote, która odpowiednio zawartość danej zmiennej modyfikowała (dodawała apostrofy itp.).
I jeszcze co do wymogów MySQL - czy podając w zapytaniu MySQL nazwę tabeli, zgodnie z wymogami, trzeba tą nazwe otoczyć jakimś cudzysłowem? I tak samo z nazwami pól/wprowadzanymi wartościami - jak jest zgodnie z MySQL - otaczać je apostrofami? Jak tak, to którymi: ' ' czy ` ` (to na tyldzie, pod esc)? Bo spotykam się z takimi skryptami, gdzie używa sie albo ', albo `, albo w ogóle, a nie wiem jak jest poprawnie smile.gif
nospor
do PDO napisalem sobie mała nakladke i ja wykonuje zapytanie tak:
  1. <?php
  2. $res = $this->Dbo->QueryPrepare($sql,array('tablica z wartosciami przekazywanymi do zapytania'));
  3. ?>
winksmiley.jpg

PDO samo quotuje wartosci.

Cytat
I jeszcze co do wymogów MySQL - czy podając w zapytaniu MySQL nazwę tabeli, zgodnie z wymogami, trzeba tą nazwe otoczyć jakimś cudzysłowem? I tak samo z nazwami pól/wprowadzanymi wartościami - jak jest zgodnie z MySQL - otaczać je apostrofami? Jak tak, to którymi: ' ' czy ` ` (to na tyldzie, pod esc)? Bo spotykam się z takimi skryptami, gdzie używa sie albo ', albo `, albo w ogóle, a nie wiem jak jest poprawnie

`` masz uzywac gdy stosujesz zastrzezone nazwy dla kolumn lub tabel
http://dev.mysql.com/doc/refman/5.0/en/reserved-words.html
Apocalyptiq
Przeczytałem manual z wiki o PDO, no i z tego co tam wyczytałem powoli rezygnuje się z mysql_query, mysql_fetch_assoc itp. A z tego co kojarze, to AdoDB właśnie z tych funkcji korzysta? Tylko posiada zbiór funkcji, ułatwiających korzystanie z tych mysql_query itp? Początkowo myślałem, że PDO to coś podobnego do AdoDB - też zbiór funkcji z tymi mysql_fetch, a tu okazuje się, że to jest osobny obiekt wbudowany w php (bodajrze od wersji 5), no i chyba właśnie nie korzystający z tamtych fetch, tylko jest to całkiem nowe rozwiązanie. Czyli to PDO chyba będzie najlepszym rozwiązaniem do MySQL smile.gif W manualu też wyczytałem o rozszerzeniu do PDO - Open Power Driver. Ułatwia bind'owanie (podmienianie w zapytaniu) zmiennych, dodaje też obsługę cache. Ale coś na stronę tego projektu (http://www.openpb.net/) nie mogę wejść :/

Zrobiłem testy czasowe tych trzech sposobów pracy z MySQL - tradycyjne mysql_fetch_assoc, AdoDB i PDO. Oto skrypty pomiarowe:

mysql_fetch_assoc:
Kod
<? function podajCzas(){
     list($usec, $sec) = explode(" ", microtime());
     return ((float)$usec + (float)$sec);
}
$start=podajCzas();
if(isset($_GET['id'])){
$sql_conn=mysql_connect('localhost', 'root', 'jo');
mysql_select_db('siatka');
$events=mysql_query('SELECT * FROM events WHERE nr>\''.mysql_real_escape_string($_GET['id']).'\'');
while($event=mysql_fetch_assoc($events)){
echo $event['event'],'<br />';
}
}
echo '<br />fetch: '.round(podajCzas()-$start,3).' sekund';
?>

AdoDB:
Kod
<? function podajCzas(){
     list($usec, $sec) = explode(" ", microtime());
     return ((float)$usec + (float)$sec);
}
$start=podajCzas();
if(isset($_GET['id'])){
require_once 'inc/db.php';
foreach($db->GetAll('SELECT * FROM events WHERE nr>'.$db->Quote($_GET['id'])) as $event)
echo $event['event'],'<br />';
}
echo '<br />adodb: '.round(podajCzas()-$start,3).' sekund';
?>

PDO:
Kod
<?php function podajCzas(){
     list($usec, $sec) = explode(" ", microtime());
     return ((float)$usec + (float)$sec);
}
$start=podajCzas();
try{
     $pdo = new PDO('mysql:host=localhost;dbname=siatka', 'root', 'jo');
     $pdo -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
     if(isset($_GET['id'])){
     $players=$pdo->prepare('SELECT * FROM events WHERE nr>:id');
     $players->bindValue(':id',$_GET['id'],PDO::PARAM_INT);
     $players->execute();
     while($player=$players->fetch())
         echo $player['event'],'<br />';
     $players->closeCursor();
     }
     }
catch(PDOException $e){
     echo 'Wystapil blad biblioteki PDO: ' . $e->getMessage();
}
echo '<br />pdo: '.round(podajCzas()-$start,3).' sekund';
?>


Wykonałem na każdym skrypcie po 14 pomiarów. Oto średnie wyniki:

mysql_fetch_assoc: 0.0259s.
AdoDB: 0.1406s.
PDO: 0.0219s

Zwyciężył nieznacznie PDO, AdoDB wyraźnie wolniejszy od swoich rywalów. I rekord czasowy należy do mysql_fetch_assoc i PDO: egzekwo - 0.004s. smile.gif

Czyli z tych pomiarów wynika, że najlepszym rozwiązaniem do pracy z MySQL jest PDO. Do tego czytałem, że w następnych wersjach PHP funkcje typu mysql_query mają być wycofane.

Dziękuję wszystkim za dyskuje w tym temacie smile.gif

Aha i jeszcze co do tego rozszerzenia Open Power Driver - używał tego ktoś kiedyś?
nrm
AdoDB to kobyła, najwolniejsza ze wszystkiego. Jak już trzeba było to wolałem AdoDBLite.
OPD - tak, używałem parę lat temu, miło wspominam.
Apocalyptiq
Poszukałem informacji o tej nakładce w necie, i okazuje się że prace nad nią zostały wstrzymane. Ale istnieją lepsze (podobno) projekty, np. PHP-Doctrine. A tego rozszerzenia ktoś kiedyś używał? smile.gif

normanos -> a teraz czego używasz do pracy z bazami danych?
nrm
tego co oferuje dany framework, przez te ostatnie lata było tego trochę (cake, CI, Rapide, ZF, Kohana).

Doctrine to ORM - trochę się z tym miotasz bo dałeś zupełnie różne rozwiązania i czekasz na opinie :0
Apocalyptiq
Czyli najlepiej z czego korzystać do obsługi baz MySQL - czystego PDO czy z jakimiś nakładkami?

I co do PDO - to przy każdej operacji na nim, trzeba się zawsze od nowa łączyć z bazą danych? na początku tego try{...
Żeby nie pisać przy każdej operacji na MySQL hasła, hosta, loginu itp. - to ten początek każdego skryptu PDO najlepiej chyba zaincludować z zewnętrznego pliku, w którym będzie to połączenie z MySQL przez PDO? Jak profesjonalni programiści to łączenie się z bazą robią?
NoiseMc
Cytat
I co do PDO - to przy każdej operacji na nim, trzeba się zawsze od nowa łączyć z bazą danych? na początku tego try{...
Żeby nie pisać przy każdej operacji na MySQL hasła, hosta, loginu itp. - to ten początek każdego skryptu PDO najlepiej chyba zaincludować z zewnętrznego pliku, w którym będzie to połączenie z MySQL przez PDO? Jak profesjonalni programiści to łączenie się z bazą robią?


To moze rzuce kodem...

  1. <?php
  2. class Base_Model
  3. {
  4.   /**
  5.     * @var PDO
  6.     */
  7.   protected $db;
  8.  
  9.   public function __construct ()
  10.   {
  11.       $config = Config::getSomeConfiguration ();
  12.  
  13.       $this->db = new Pdo ('mysql:host=' . $config->database->host . ';dbname=' . $config->database->dbname . '', $config->database->username, $config->database->password);
  14.      
  15.       $this->db->setAttribute (PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  16.       $this->db->setAttribute (PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
  17.   }
  18. }
  19. ?>


  1. <?php
  2. class Cities_Model extends Base_Model
  3. {
  4.    /**
  5.      * @return Cities_City
  6.      */
  7.    public function getByID ($cityID)
  8.    {
  9.        $query  = 'SELECT * FROM cities WHERE cityID = ?';
  10.  
  11.        $statement = $this->db->prepare ($query);
  12.                    
  13.        $statement->bindParam (1, $cityID);
  14.            
  15.        $statement->execute ();
  16.        
  17.        $city = $statement->fetch ();          
  18.        
  19.        return $city;
  20.    }
  21.    
  22.    /**
  23.      * @return array ()
  24.      */
  25.    public function getAll ()
  26.    {
  27.        $query  = 'SELECT * FROM cities ORDER BY name ASC';
  28.  
  29.        $statement = $this->db->prepare ($query);
  30.            
  31.        $statement->execute ();
  32.        
  33.        $cities = array ();
  34.        
  35.        while (($city = $statement->fetch ()) !== false)
  36.        {
  37.            $cities[] = $city;
  38.        }
  39.        
  40.        return $cities;
  41.    }
  42. }
  43. ?>


a potem tylko ...

  1. <?php
  2. $citiesModel = new Cities_Model ();
  3.  
  4. foreach ($citiesModel->getAll () as $city)
  5. {
  6.    print ($city['name'] . '<br />');
  7. }
  8. ?>
zzeus
Można też na początku skryptu nawiązywać połączenie i ustawić to jako zmienną globalną, ale nie wiem który sposób lepszy smile.gif
Apocalyptiq
A jak działa to:
Kod
$config = Config::getSomeConfiguration ();
? Trzeba zdefiniowac klase z funkcją getSomeConfiguration, która zwraca ustawienia serwera MySQL (jako tablice chyba nie, to jak?) ? A nie lepiej po prostu wpisać tam ten host, login itp. bezpośrednio? I tak tylko raz - w głównej klasie bazy - będzie się to ustawiać. I jakoś w tych klasach nie widze tego try{} catch{} - czyli to nie jest konieczne?

I co włącza ta linijka:
Kod
$this->db->setAttribute (PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
?

NoiseMc -> zmodyfikowałem nieco twój kod:
Kod
class Base{
     protected $db;
     public function __construct(){
         $this->db = new Pdo('mysql:host=localhost;dbname=siatka','root','jo');
         $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
         $this->db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, 1);
     }
}

class Database extends Base{
     public function sql($query, $binds=null, $rows=null){
         $statement=$this->db->prepare($query);
         if($binds!=null){
             if(is_array($binds)){
                 foreach($binds as $n => $bind)
                     $statement->bindValue(($n+1), $bind);
             } else
                 $statement->bindValue(1, $binds);
         }
         $statement->execute();
         if($rows==null){
             $results=array();
             while($result=$statement->fetch())
                 $results[]=$result;
             return $results;
         } elseif($rows==1){
             if($result=$statement->fetch())
                 return $result;
         } elseif($rows=="one"){
             if($result=$statement->fetch())
                 return $result[0];
         }
     }
}

Teraz gdy chce pobrać wynik jakiegoś zapytania, piszę np.:
Kod
$db = new Database();
   $players=$db->getAll('SELECT * FROM players WHERE wzrost>? AND wiek>?',array(180,18)));


Proszę o zerknięcie na tą klasę - jest poprawna, można jej spokojnie używać?

Wywołanie:
Kod
$db = new Database();

Nie wykonuje od razu na początku każdej strony (od razu pod klasami Base i Database), tylko przed zapytaniem, jeżeli takie chce wykonać? Niby możnaby to utworzenie objektu includować razem z klasą bazy, ale jeżeli na danej podstronie nie będzie się korzystać z bazy - to niepotrzebnie będzie to chyba zajmować serwer?
Proszę o radę profesjonalnych programistów pracujących z PDO - połączenie z bazą dawać na początku index.php, czy tylko przed zapytaniami które chcemy wykonać?
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.