core/benchmarks/pagination_test.go

330 lines
7.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package benchmarks
import (
"database/sql"
"log"
"testing"
_ "github.com/lib/pq"
)
const (
accountID = "64f2cd7a7047f28fdabf6d9e"
connStr = "host=localhost port=35432 user=squiz password=Redalert2 dbname=squiz sslmode=disable"
queryTotal = `
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT f.*, COUNT(*) OVER() as total_count
FROM fields f JOIN user_data u ON f.AccountID = u.AmoID
WHERE f.Deleted = false
ORDER BY f.ID OFFSET ($2 - 1) * $3 LIMIT $3;
`
queryCount = `
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT COUNT(*)
FROM fields f JOIN user_data u ON f.AccountID = u.AmoID
WHERE f.Deleted = false;
`
queryData = `
WITH user_data AS (
SELECT AmoID FROM accountsAmo WHERE accountsAmo.AccountID = $1 AND accountsAmo.Deleted = false
)
SELECT f.*
FROM fields f JOIN user_data u ON f.AccountID = u.AmoID
WHERE f.Deleted = false
ORDER BY f.ID OFFSET ($2 - 1) * $3 LIMIT $3;
`
)
type GetFieldsWithPaginationRow struct {
ID int64 `db:"id" json:"id"`
Amoid int32 `db:"amoid" json:"amoid"`
Code string `db:"code" json:"code"`
Accountid int32 `db:"accountid" json:"accountid"`
Name string `db:"name" json:"name"`
Entity interface{} `db:"entity" json:"entity"`
Type interface{} `db:"type" json:"type"`
Deleted bool `db:"deleted" json:"deleted"`
Createdat sql.NullTime `db:"createdat" json:"createdat"`
TotalCount int64 `db:"total_count" json:"total_count"`
}
func initDB() *sql.DB {
db, err := sql.Open("postgres", connStr)
if err != nil {
log.Fatal(err)
}
return db
}
// Все получаем в одном запросе не аллоцируя при этом массив
func BenchmarkAllOne(b *testing.B) {
db := initDB()
defer db.Close()
for i := 0; i < b.N; i++ {
page := 1
size := 25
rows, err := db.Query(queryTotal, accountID, page, size)
if err != nil {
b.Fatal(err)
}
defer rows.Close()
var results []GetFieldsWithPaginationRow
for rows.Next() {
var row GetFieldsWithPaginationRow
if err := rows.Scan(
&row.ID,
&row.Amoid,
&row.Code,
&row.Accountid,
&row.Name,
&row.Entity,
&row.Type,
&row.Deleted,
&row.Createdat,
&row.TotalCount,
); err != nil {
b.Fatal(err)
}
results = append(results, row)
}
if err := rows.Err(); err != nil {
b.Fatal(err)
}
}
}
// Все получаем в одном запросе аллоцируя при этом массив
func BenchmarkAllOnePreAllocation(b *testing.B) {
db := initDB()
defer db.Close()
for i := 0; i < b.N; i++ {
page := 1
size := 25
rows, err := db.Query(queryTotal, accountID, page, size)
if err != nil {
b.Fatal(err)
}
defer rows.Close()
results := make([]GetFieldsWithPaginationRow, size)
for rows.Next() {
var row GetFieldsWithPaginationRow
if err := rows.Scan(
&row.ID,
&row.Amoid,
&row.Code,
&row.Accountid,
&row.Name,
&row.Entity,
&row.Type,
&row.Deleted,
&row.Createdat,
&row.TotalCount,
); err != nil {
b.Fatal(err)
}
results = append(results, row)
}
if err := rows.Err(); err != nil {
b.Fatal(err)
}
}
}
// Считается сначала количество потом получаются данные длину и емкость массиву не меняем
func BenchmarkCountThenGetData(b *testing.B) {
db := initDB()
defer db.Close()
for i := 0; i < b.N; i++ {
page := 1
size := 25
row := db.QueryRow(queryCount, accountID)
var totalCount int
if err := row.Scan(&totalCount); err != nil {
b.Fatal(err)
}
var results []GetFieldsWithPaginationRow
rows, err := db.Query(queryData, accountID, page, size)
if err != nil {
b.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var row GetFieldsWithPaginationRow
if err := rows.Scan(
&row.ID,
&row.Amoid,
&row.Code,
&row.Accountid,
&row.Name,
&row.Entity,
&row.Type,
&row.Deleted,
&row.Createdat,
); err != nil {
b.Fatal(err)
}
results = append(results, row)
}
if err := rows.Err(); err != nil {
b.Fatal(err)
}
}
}
// Параллельное вычисление данных и общего количество при этом длина слайса = size
func BenchmarkParallel(b *testing.B) {
db := initDB()
defer db.Close()
for i := 0; i < b.N; i++ {
page := 1
size := 25
results := make([]GetFieldsWithPaginationRow, size)
channel := make(chan error, 2)
go func() {
row := db.QueryRow(queryCount, accountID)
var totalCount int
channel <- row.Scan(&totalCount)
}()
go func() {
rows, err := db.Query(queryData, accountID, page, size)
if err != nil {
channel <- err
return
}
defer rows.Close()
index := 0
for rows.Next() {
if err := rows.Scan(
&results[index].ID,
&results[index].Amoid,
&results[index].Code,
&results[index].Accountid,
&results[index].Name,
&results[index].Entity,
&results[index].Type,
&results[index].Deleted,
&results[index].Createdat,
); err != nil {
channel <- err
return
}
index++
}
channel <- rows.Err()
}()
for i := 0; i < 2; i++ {
if err := <-channel; err != nil {
b.Fatal(err)
}
}
}
}
// Считается сначала количество потом получаются данные создаем слайс через маке указывая ему длину начальную кап = лен
func BenchmarkWithPreAllocation(b *testing.B) {
db := initDB()
defer db.Close()
for i := 0; i < b.N; i++ {
page := 1
size := 25
results := make([]GetFieldsWithPaginationRow, size)
row := db.QueryRow(queryCount, accountID)
var totalCount int
if err := row.Scan(&totalCount); err != nil {
b.Fatal(err)
}
rows, err := db.Query(queryData, accountID, page, size)
if err != nil {
b.Fatal(err)
}
defer rows.Close()
index := 0
for rows.Next() {
if err := rows.Scan(
&results[index].ID,
&results[index].Amoid,
&results[index].Code,
&results[index].Accountid,
&results[index].Name,
&results[index].Entity,
&results[index].Type,
&results[index].Deleted,
&results[index].Createdat,
); err != nil {
b.Fatal(err)
}
index++
}
if err := rows.Err(); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkWithPreAllocationAndMonitoringTotalCount(b *testing.B) {
db := initDB()
defer db.Close()
for i := 0; i < b.N; i++ {
page := 1
size := 50
row := db.QueryRow(queryCount, accountID)
var totalCount int
if err := row.Scan(&totalCount); err != nil {
b.Fatal(err)
}
if totalCount < size {
size = totalCount
}
results := make([]GetFieldsWithPaginationRow, size)
rows, err := db.Query(queryData, accountID, page, size)
if err != nil {
b.Fatal(err)
}
defer rows.Close()
index := 0
for rows.Next() {
if err := rows.Scan(
&results[index].ID,
&results[index].Amoid,
&results[index].Code,
&results[index].Accountid,
&results[index].Name,
&results[index].Entity,
&results[index].Type,
&results[index].Deleted,
&results[index].Createdat,
); err != nil {
b.Fatal(err)
}
index++
}
if err := rows.Err(); err != nil {
b.Fatal(err)
}
}
}