sql >> Databasteknik >  >> RDS >> PostgreSQL

Varför ens använda *DB.exec() eller förberedda uttalanden i Golang?

"Varför ens använda db.Exec()":

Det är sant att du kan använda db.Exec och db.Query omväxlande för att köra samma SQL-satser, men de två metoderna returnerar olika typer av resultat. Om det implementeras av drivrutinen returneras resultatet från db.Exec kan berätta hur många rader som påverkades av frågan, medan db.Query returnerar radobjektet istället.

Låt oss till exempel säga att du vill köra en DELETE uttalande och du vill veta hur många rader som raderades av den. Du kan göra det antingen på rätt sätt:

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)

eller det mer omfattande och objektivt dyrare sättet:

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)

Det finns ett tredje sätt att göra detta med en kombination av postgres CTE, SELECT COUNT , db.QueryRow och row.Scan men jag tror inte att ett exempel är nödvändigt för att visa hur orimligt ett tillvägagångssätt det skulle vara jämfört med db.Exec .

Ytterligare ett skäl att använda db.Exec över db.Query är när du inte bryr dig om det returnerade resultatet, när allt du behöver är att köra frågan och kontrollera om det var ett fel eller inte. I ett sådant fall kan du göra detta:

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

Å andra sidan kan du inte (du kan men du borde inte) göra detta:

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

Om du gör detta kommer ditt program efter en kort stund att få panik med ett felmeddelande som säger något som liknar too many connections open . Detta beror på att du kasserar de returnerade db.Rows utan att först göra den obligatoriska Close anropa det, och så slutar du med att antalet öppna anslutningar ökar och så småningom når serverns gräns.

"eller förberedda uttalanden i Golang?":

Jag tror inte att boken du citerade är korrekt. Åtminstone för mig ser det ut som om det är en db.Query eller inte call skapar en ny förberedd sats varje gång beror på vilken drivrutin du använder.

Se till exempel dessa två avsnitt av queryDC (en oexporterad metod som anropas av db.Query ):utan förberett utlåtande och med förberett utlåtande.

Oavsett om boken är korrekt eller inte en db.Stmt skapad av db.Query skulle, om det inte pågår någon intern cachning, kastas efter att du stänger de returnerade Rows objekt. Om du istället manuellt ringer db.Prepare och cache och återanvänd den returnerade db.Stmt du kan eventuellt förbättra prestandan för de frågor som måste köras ofta.

För att förstå hur ett förberett uttalande kan användas för att optimera prestanda kan du ta en titt på den officiella dokumentationen:https://www.postgresql.org/docs/current/static/sql-prepare.html




  1. Oracle CREATE TABLE-kommando i PL/SQL med 10 exempel

  2. SQL-fråga med flera värden i en cell

  3. Kan inte validera, med novalidate-alternativet

  4. Lagra data i MySQL som JSON