sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Por qué incluso usar *DB.exec() o declaraciones preparadas en Golang?

"¿Por qué incluso usar db.Exec()":

Es cierto que puedes usar db.Exec y db.Query indistintamente para ejecutar las mismas sentencias sql; sin embargo, los dos métodos devuelven diferentes tipos de resultados. Si lo implementa el controlador, el resultado devuelto por db.Exec puede decirle cuántas filas se vieron afectadas por la consulta, mientras que db.Query devolverá el objeto de filas en su lugar.

Por ejemplo, supongamos que desea ejecutar un DELETE y desea saber cuántas filas eliminó. Puedes hacerlo de la manera correcta:

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 la forma más detallada y objetivamente más costosa:

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)

Hay una tercera forma de hacer esto con una combinación de CTE de postgres, SELECT COUNT , db.QueryRow y row.Scan pero no creo que sea necesario un ejemplo para mostrar cuán irrazonable sería un enfoque en comparación con db.Exec .

Otra razón para usar db.Exec sobre db.Query es cuando no le importa el resultado devuelto, cuando todo lo que necesita es ejecutar la consulta y verificar si hubo un error o no. En tal caso, puede hacer esto:

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

Por otro lado, no puedes (puedes pero no debes) hacer esto:

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

Al hacer esto, después de un rato, su programa entrará en pánico con un error que dice algo parecido a too many connections open . Esto se debe a que está descartando las db.Rows devueltas. valor sin hacer primero el obligatorio Close llámalo, y así terminas con el número de conexiones abiertas aumentando y eventualmente alcanzando el límite del servidor.

"¿o declaraciones preparadas en Golang?":

No creo que el libro que has citado sea correcto. Al menos a mí me parece si un db.Query call crea una nueva declaración preparada cada vez que depende del controlador que esté utilizando.

Vea por ejemplo estas dos secciones de queryDC (un método no exportado llamado por db.Query ):sin sentencia preparada y con sentencia preparada.

Independientemente de si el libro es correcto o no, un db.Stmt creado por db.Query sería, a menos que haya algún almacenamiento en caché interno en marcha, descartado después de cerrar las Rows devueltas objeto. Si, en cambio, llama manualmente a db.Prepare y luego almacenar en caché y reutilizar el db.Stmt devuelto puede mejorar potencialmente el rendimiento de las consultas que deben ejecutarse con frecuencia.

Para comprender cómo se puede usar una declaración preparada para optimizar el rendimiento, puede consultar la documentación oficial:https://www.postgresql.org/docs/current/static/sql-prepare.html