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