2016-02-26 6 views
7

Provare a scrivere qualcosa per convertire automaticamente da un risultato DB arbitrario (ad esempio, non sempre tutto dalla tabella x), a un risultato tipizzato PHP appropriato.Ottieni tipi di colonna tramite PDO (getColumnMeta è/lento /)

ho esteso la classe PDOStatement,

class Statement extends PDOStatement { 
    protected $pdo; 
    protected $transformer; 

    protected function __construct(PDO $pdo) { 
     $this->pdo = $pdo; 
     $this->transformer = $pdo->getTransformer(); 
    } 

    public function fetchAll() { 
     $results = parent::fetchAll(PDO::FETCH_ASSOC); 

     if ($this->getTransformer()) $results = $this->completeResults($results); 

     return $results; 
    } 

    private function completeResults(array $results = []) { 
     if ($results == null || count($results) == 0) return null; 
     if ($results[0] == false || !is_array($results[0])) return null; 

     $index = 0; 
     $typeMap = []; 

     foreach ($results[0] as $column => $result) { 
      $meta = $this->getColumnMeta($index); // this is very painful 
      $typeMap[$column] = $meta['native_type']; 
      $index++; 
     } 

     $transformer = $this->getTransformer(); 
     foreach ($results as $index => &$result) { 
      array_walk($result, function(&$value, $key) use ($typeMap, $transformer) { 
       $type = $typeMap[$key]; 
       $value = $transformer->transformToPhpValue($value, $type); 
      }); 
     } 

     return $results; 
    } 
} 

In precedenza, prima che io ero a conoscenza della DOP astrazione, stavo usando (nel mio caso specifico) il pg di serie _... metodi(). Usando pg_field_type($resource, $column);, ho potuto recuperare il tipo di colonna, ed era relativamente veloce.

Ora, utilizzando il nuovo metodo (per me) PDO. Se io commento la parte del mio codice dove faccio la trasformazione, e corro 7 query consecutive:

time to complete: 9.5367431640625E-7 seconds 
time to complete: 1.1920928955078E-6 seconds 
time to complete: 9.5367431640625E-7 seconds 
time to complete: 0 seconds 
time to complete: 9.5367431640625E-7 seconds 
time to complete: 0 seconds 
time to complete: 0 seconds 

con esso abilitati:

time to complete: 0.5777850151062 seconds 
time to complete: 0.49124097824097 seconds 
time to complete: 0.28375911712646 seconds 
time to complete: 0.5946729183197 seconds 
time to complete: 0.42177200317383 seconds 
time to complete: 5.0067901611328E-6 seconds 
time to complete: 0.42121982574463 seconds 

Ecco// folle.

posso dire che è andare a prendere le informazioni di colonna ad uno ad uno per uno, cercando in miei log Postgres:

LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=1114 
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=1114 
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=25 
... like 30 more of these ... 
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=25 
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=23 
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=23 
LOG: statement: SELECT TYPNAME FROM PG_TYPE WHERE OID=23 

Le query variano in complessità da

SELECT 
    p.modified_at, ... ~ 30 fields ..., r.level AS id_level 
FROM table_p AS p 
LEFT JOIN table_a AS a ON (p.owner = a.id) 
LEFT JOIN table_a0 AS a0 ON (p.reporter = a0.id) 
LEFT JOIN table_r AS r ON (p.id = r.id) 
WHERE (p.id = 1) 

a poco SELECT * FROM table_a AS a;

Quindi, suppongo che la domanda sia: c'è un modo migliore per farlo? C'è un modo per farlo senza influire sulla velocità del mio codice? 7 query sono sulla fascia bassa di query consecutive eseguite per richiesta, quindi è qualcosa che vorrei affrontare.

+1

Credo che per ora, faresti meglio a farlo usando php perché è ancora sperimentale. Sarà l'anno luce più veloce. – cpugourou

+0

Se si prevede di utilizzare solo Postgresql per il proprio progetto, si consiglia vivamente di utilizzare la libreria pgsql nativa al posto di PDO. La PDO è più lenta ed espone meno funzioni. Una risposta per il tuo tipo di problema potrebbe essere http://stackoverflow.com/questions/31643297/pg-query-result-contains-strings-instead-of-integer-numeric/31740990#31740990 – greg

+0

@greg yeah questo è quello che stavo usando prima. Sfortunatamente voleva dire scrivere molte delle funzionalità con cui PDO viene fornito con ... –

risposta

1

Prima di tutto, è PDOStatement::getColumnMeta()sperimentale, in modo da essere molto attenti con esso (si spera faranno Autotest di impostazione di controllare questo con qualsiasi versione di aggiornamento php/DOP).

quanto riguarda la velocità di recupero dei metadati, ho eseguito alcuni test e si scopre che SELECT TYPNAME FROM PG_TYPE WHERE OID=% query vengono eseguite ardente veloce:

explain analyze SELECT TYPNAME FROM PG_TYPE WHERE OID=25; 
                 QUERY PLAN               
---------------------------------------------------------------------------------------------------------------------------- 
Index Scan using pg_type_oid_index on pg_type (cost=0.27..8.29 rows=1 width=64) (actual time=0.051..0.055 rows=1 loops=1) 
    Index Cond: (oid = 25::oid) 
Planning time: 0.165 ms 
Execution time: 0.100 ms 
(4 rows) 

explain analyze SELECT TYPNAME FROM PG_TYPE WHERE OID=1114; 
                 QUERY PLAN               
---------------------------------------------------------------------------------------------------------------------------- 
Index Scan using pg_type_oid_index on pg_type (cost=0.27..8.29 rows=1 width=64) (actual time=0.083..0.085 rows=1 loops=1) 
    Index Cond: (oid = 1114::oid) 
Planning time: 0.192 ms 
Execution time: 0.139 ms 
(4 rows) 

explain analyze SELECT TYPNAME FROM PG_TYPE WHERE OID=600; 
                 QUERY PLAN               
---------------------------------------------------------------------------------------------------------------------------- 
Index Scan using pg_type_oid_index on pg_type (cost=0.27..8.29 rows=1 width=64) (actual time=0.063..0.064 rows=1 loops=1) 
    Index Cond: (oid = 600::oid) 
Planning time: 0.261 ms 
Execution time: 0.125 ms 
(4 rows) 

Questo è di circa 0,0001 secondi per PG per selezionare i dati, anche sommando 30 di questi non si sommano in 0,5 secondi o qualcosa del genere.

Si consiglia di eseguire explain analyze sul server per le query pg_type e vedere quali sono i tempi lì.

Scommetti che non stai utilizzando una connessione persistente a un DB, e che aggiunge un sacco di tempo alle tue chiamate di metadati.

Problemi correlati