2013 подписчиков
👣 Хитрый способ в 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, но помнить что строки могут и перемещаются как внутри блока, так и между ними
1 минута
28 февраля 2024