sql >> Databáze >  >> RDS >> PostgreSQL

Proč vůbec používat *DB.exec() nebo připravené příkazy v Golangu?

"Proč vůbec používat db.Exec()":

Je pravda, že můžete použít db.Exec a db.Query zaměnitelně provádět stejné příkazy SQL, ale tyto dvě metody vracejí různé typy výsledků. Pokud je implementován ovladačem, vrátí výsledek db.Exec vám může říct, kolik řádků bylo ovlivněno dotazem, zatímco db.Query místo toho vrátí objekt rows.

Řekněme například, že chcete provést DELETE a chcete vědět, kolik řádků bylo odstraněno. Můžete to udělat buď správným způsobem:

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)

nebo podrobnější a objektivně nákladnější způsob:

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)

Existuje třetí způsob, jak to udělat pomocí kombinace postgresových CTE, SELECT COUNT , db.QueryRow a row.Scan ale nemyslím si, že příklad je nutný, aby ukázal, jak nerozumný přístup by byl ve srovnání s db.Exec .

Další důvod, proč používat db.Exec přes db.Query je, když se nestaráte o vrácený výsledek, kdy vše, co potřebujete, je provést dotaz a zkontrolovat, zda došlo k chybě nebo ne. V takovém případě můžete provést toto:

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

Na druhou stranu nemůžete (můžete, ale neměli byste) udělat toto:

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

Když to uděláte, po krátké chvíli váš program zpanikaří s chybou, která říká něco podobného too many connections open . Je to proto, že zahazujete vrácené db.Rows hodnotu bez předchozího zadání povinného Close zavolejte na něj a tak skončíte s tím, že počet otevřených spojení naroste a nakonec narazí na limit serveru.

"nebo připravené příkazy v Golang?":

Nemyslím si, že kniha, kterou citujete, je správná. Alespoň pro mě to vypadá jako zda db.Query call vytvoří nový připravený příkaz pokaždé, když to závisí na ovladači, který používáte.

Viz například tyto dvě části queryDC (neexportovaná metoda volaná db.Query ):bez připraveného výpisu a s připraveným výpisem.

Bez ohledu na to, zda je kniha správná nebo ne, db.Stmt vytvořil db.Query bude, pokud neprobíhá nějaké interní ukládání do mezipaměti, po zavření vrácených Rows zahozen objekt. Pokud místo toho ručně zavoláte db.Prepare a poté uložte a znovu použijte vrácený db.Stmt můžete potenciálně zlepšit výkon dotazů, které je třeba provádět často.

Chcete-li pochopit, jak lze připravené prohlášení použít k optimalizaci výkonu, můžete se podívat na oficiální dokumentaci:https://www.postgresql.org/docs/current/static/sql-prepare.html




  1. mysql dvousloupcový primární klíč s automatickým přírůstkem

  2. Jak resetovat AUTO_INCREMENT v MySQL

  3. Co jsou zámky řádků, stránek a tabulek? A kdy jsou pořízeny?

  4. Přehled změn indexu v PostgreSQL 11