PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Perché usare *DB.exec() o istruzioni preparate in Golang?

"Perché anche usare db.Exec()":

È vero che puoi usare db.Exec e db.Query in modo intercambiabile per eseguire le stesse istruzioni sql, tuttavia i due metodi restituiscono diversi tipi di risultati. Se implementato dal driver il risultato restituito da db.Exec può dirti quante righe sono state interessate dalla query, mentre db.Query restituirà invece l'oggetto righe.

Ad esempio, supponiamo che tu voglia eseguire un DELETE istruzione e vuoi sapere quante righe sono state cancellate da essa. Puoi farlo nel modo corretto:

res, err := db.Exec(`DELETE FROM my_table WHERE expires_at = $1`, time.Now())
if err != nil {
    panic(err)
}

numDeleted, err := res.RowsAffected()
if err != nil {
    panic(err)
}
print(numDeleted)

o il modo più dettagliato e oggettivamente più costoso:

rows, err := db.Query(`DELETE FROM my_table WHERE expires_at = $1 RETURNING *`, time.Now())
if err != nil {
    panic(err)
}
defer rows.Close()

var numDelete int
for rows.Next() {
    numDeleted += 1
}
if err := rows.Err(); err != nil {
    panic(err)
}
print(numDeleted)

C'è un terzo modo per farlo con una combinazione di CTE postgres, SELECT COUNT , db.QueryRow e row.Scan ma non credo sia necessario un esempio per mostrare quanto sarebbe irragionevole un approccio rispetto a db.Exec .

Un altro motivo per usare db.Exec su db.Query è quando non ti interessa il risultato restituito, quando tutto ciò di cui hai bisogno è eseguire la query e verificare se si è verificato un errore o meno. In tal caso puoi farlo:

if _, err := db.Exec(`<my_sql_query>`); err != nil {
    panic(err)
}

D'altra parte, non puoi (puoi ma non dovresti) fare questo:

if _, err := db.Query(`<my_sql_query>`); err != nil {
    panic(err)
}

In questo modo, dopo un po', il tuo programma andrà nel panico con un errore che dice qualcosa di simile a too many connections open . Questo perché stai eliminando il db.Rows restituito valore senza prima rendere obbligatorio il Close chiamalo e così il numero di connessioni aperte aumenta e alla fine raggiunge il limite del server.

"o dichiarazioni preparate in Golang?":

Non credo che il libro che hai citato sia corretto. Almeno a me sembra o meno un db.Query call crea una nuova dichiarazione preparata ogni volta che dipende dal driver che stai utilizzando.

Vedi ad esempio queste due sezioni di queryDC (un metodo non esportato chiamato da db.Query ):senza dichiarazione preparata e con dichiarazione preparata.

Indipendentemente dal fatto che il libro sia corretto o meno un db.Stmt creato da db.Query sarebbe, a meno che non sia in corso una memorizzazione nella cache interna, eliminata dopo aver chiuso le Rows restituite oggetto. Se invece chiami manualmente db.Prepare quindi memorizza nella cache e riutilizza il db.Stmt restituito puoi potenzialmente migliorare le prestazioni delle query che devono essere eseguite spesso.

Per capire come utilizzare una dichiarazione preparata per ottimizzare le prestazioni puoi dare un'occhiata alla documentazione ufficiale:https://www.postgresql.org/docs/current/static/sql-prepare.html