Хитрый способ в PostgreSQL перебрать всю таблицу медленно и аккуратно, но эффективно, используя указатель ссылающийся на конкретный tuple - ctid.
var endBlock int
row := db.QueryRow(ctx, `select relpages from pg_class where oid = 'table1'::regclass::oid`)
err = row.Scan(&endBlock)
if err != nil {
return
}
startBlock := 0
blocksPerIteration := 50
maxTuplesPerBlock := 150
for {
var rows pgx.Rows
rows, err = db.Query(ctx, `
select id
from table1
where ctid = any (
array(
select format('(%s, %s)', a, b)::tid
from generate_series($1::int, $2::int) a(a)
cross join generate_series(0, $3) b(b)
))
and value = '100000'`,
startBlock,
startBlock+blocksPerIteration,
maxTuplesPerBlock,
)
if err != nil {
return
}
var id int
for rows.Next() {
err = rows.Scan(&id)
if err != nil {
return
}
slog.Info("found row", "id", id)
}
rows.Close()
startBlock += blocksPerIteration
if startBlock > endBlock {
break
}
time.Sleep(100 * time.Millisecond)
}
Нюансы:
из-за того что тип
tid
не оптимизирует операции больше/меньше, приходится использоватьctid = any (...)
для определения
maxTuplesPerBlock
можно использовать запрос
select 8096 / min(x)
from (
select pg_column_size(table1) x
from table1 tablesample system(1)
) d
можно делать не только
select
, но иupdate
иdelete
, но помнить что строки могут и перемещаются как внутри блока, так и между ними