Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
206 changes: 155 additions & 51 deletions example/src/benchmarks/readCases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {

const NARROW_ROWS = 10000
const WIDE_ROWS = 300000
const FRACTIONAL_ROWS = 100000
const POINT_READS = 1000
const CHUNK_SIZE = 1000
const NARROW_SCHEMA =
Expand All @@ -18,6 +19,35 @@ const WIDE_INSERT =
'INSERT INTO Test VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'
const WIDE_SCHEMA =
'CREATE TABLE Test (id INT PRIMARY KEY, v1 TEXT, v2 TEXT, v3 TEXT, v4 TEXT, v5 TEXT, v6 INT, v7 INT, v8 INT, v9 INT, v10 INT, v11 REAL, v12 REAL, v13 REAL, v14 REAL) STRICT'
const FRACTIONAL_SCHEMA =
'CREATE TABLE Bench (id INTEGER PRIMARY KEY, price REAL NOT NULL, ratio REAL NOT NULL, latitude REAL NOT NULL, longitude REAL NOT NULL) STRICT'
const FRACTIONAL_INSERT = 'INSERT INTO Bench VALUES (?, ?, ?, ?, ?)'

type NarrowRow = { id: number; name: string; value: number }
type WideRow = {
id: number
v1: string
v2: string
v3: string
v4: string
v5: string
v6: number
v7: number
v8: number
v9: number
v10: number
v11: number
v12: number
v13: number
v14: number
}
type FractionalRow = {
id: number
price: number
ratio: number
latitude: number
longitude: number
}

const lookupIds = Array.from(
{ length: POINT_READS },
Expand All @@ -38,13 +68,29 @@ export const readCases: BenchmarkCase[] = [
{
id: 'read-narrow',
label: '10k narrow rows · full read + access',
setup: setupNarrowRead,
setup: () => setupNarrowRead(false),
},
{
id: 'read-wide',
label: '300k wide rows · full read + access',
measuredRuns: 3,
setup: setupWideRead,
setup: () => setupWideRead(false),
},
{
id: 'read-narrow-async',
label: '10k narrow rows · async read + access',
setup: () => setupNarrowRead(true),
},
{
id: 'read-wide-async',
label: '300k wide rows · async read + access',
measuredRuns: 3,
setup: () => setupWideRead(true),
},
{
id: 'read-fractional',
label: '100k fractional REAL rows · full read + access',
setup: setupFractionalRead,
},
]

Expand Down Expand Up @@ -98,25 +144,33 @@ async function setupPointReads(prepared: boolean): Promise<BenchmarkFixture> {
}
}

async function setupNarrowRead(): Promise<BenchmarkFixture> {
const db = createBenchmarkDatabase('benchmark_narrow', NARROW_SCHEMA)
async function setupNarrowRead(
asynchronous: boolean,
): Promise<BenchmarkFixture> {
const db = createBenchmarkDatabase(
asynchronous ? 'benchmark_narrow_async' : 'benchmark_narrow',
NARROW_SCHEMA,
)
try {
await seedNarrowRows(db)
let count = 0
let checksum = 0
const access = (rows: NarrowRow[]) => {
count = rows.length
checksum = 0
for (const row of rows) checksum += row.id + row.value + row.name.length
}

return {
database: db,
run: () => {
const rows = db.execute<{
id: number
name: string
value: number
}>('SELECT * FROM Bench').rows._array
count = rows.length
checksum = 0
for (const row of rows) checksum += row.id + row.value + row.name.length
},
run: asynchronous
? async () =>
access(
(await db.executeAsync<NarrowRow>('SELECT * FROM Bench')).rows
._array,
)
: () =>
access(db.execute<NarrowRow>('SELECT * FROM Bench').rows._array),
verify: () => {
assertBenchmark(count === NARROW_ROWS, 'Wrong narrow read row count')
assertBenchmark(
Expand All @@ -132,8 +186,10 @@ async function setupNarrowRead(): Promise<BenchmarkFixture> {
}
}

async function setupWideRead(): Promise<BenchmarkFixture> {
const db = open({ name: 'benchmark_wide' })
async function setupWideRead(asynchronous: boolean): Promise<BenchmarkFixture> {
const db = open({
name: asynchronous ? 'benchmark_wide_async' : 'benchmark_wide',
})
try {
resetLargeDbSchema(db)
let expected = 0
Expand All @@ -147,52 +203,91 @@ async function setupWideRead(): Promise<BenchmarkFixture> {
await db.executeBatchAsync([{ query: WIDE_INSERT, params }])
}

let count = 0
let checksum = 0
const access = (rows: WideRow[]) => {
count = rows.length
checksum = 0
for (const row of rows) {
checksum +=
row.id +
row.v1.length +
row.v2.length +
row.v3.length +
row.v4.length +
row.v5.length +
row.v6 +
row.v7 +
row.v8 +
row.v9 +
row.v10 +
row.v11 +
row.v12 +
row.v13 +
row.v14
}
}
return {
database: db,
run: asynchronous
? async () =>
access(
(await db.executeAsync<WideRow>('SELECT * FROM Test')).rows
._array,
)
: () => access(db.execute<WideRow>('SELECT * FROM Test').rows._array),
verify: () => {
assertBenchmark(count === WIDE_ROWS, 'Wrong wide read row count')
assertBenchmark(checksum === expected, 'Wrong wide read checksum')
},
dispose: () => disposeBenchmarkDatabase(db),
}
} catch (error) {
disposeBenchmarkDatabase(db)
throw error
}
}

// The wide table stores whole numbers in its REAL columns. These rows store
// fractional values, which take a slower formatting path in native code.
async function setupFractionalRead(): Promise<BenchmarkFixture> {
const db = createBenchmarkDatabase('benchmark_fractional', FRACTIONAL_SCHEMA)
try {
let expected = 0
for (let start = 0; start < FRACTIONAL_ROWS; start += CHUNK_SIZE) {
const params: SQLiteQueryParams[] = []
for (
let i = start;
i < Math.min(start + CHUNK_SIZE, FRACTIONAL_ROWS);
i++
) {
const [price, ratio, latitude, longitude] = fractionalRow(i)
params.push([i, price, ratio, latitude, longitude])
expected += price + ratio + latitude + longitude
}
await db.executeBatchAsync([{ query: FRACTIONAL_INSERT, params }])
}

let count = 0
let checksum = 0
return {
database: db,
run: () => {
const rows = db.execute<{
id: number
v1: string
v2: string
v3: string
v4: string
v5: string
v6: number
v7: number
v8: number
v9: number
v10: number
v11: number
v12: number
v13: number
v14: number
}>('SELECT * FROM Test').rows._array
const rows = db.execute<FractionalRow>(
'SELECT * FROM Bench ORDER BY id',
).rows._array
count = rows.length
checksum = 0
for (const row of rows) {
checksum +=
row.id +
row.v1.length +
row.v2.length +
row.v3.length +
row.v4.length +
row.v5.length +
row.v6 +
row.v7 +
row.v8 +
row.v9 +
row.v10 +
row.v11 +
row.v12 +
row.v13 +
row.v14
checksum += row.price + row.ratio + row.latitude + row.longitude
}
},
verify: () => {
assertBenchmark(count === WIDE_ROWS, 'Wrong wide read row count')
assertBenchmark(checksum === expected, 'Wrong wide read checksum')
assertBenchmark(
count === FRACTIONAL_ROWS,
'Wrong fractional read row count',
)
assertBenchmark(checksum === expected, 'Wrong fractional read checksum')
},
dispose: () => disposeBenchmarkDatabase(db),
}
Expand Down Expand Up @@ -240,3 +335,12 @@ function wideRow(i: number): SQLiteQueryParams {
function wideRowChecksum(i: number): number {
return 10 * i + 36 + 5 * `n${i % 1000}`.length
}

function fractionalRow(i: number): [number, number, number, number] {
return [
(i % 100000) / 100 + 0.005,
i / 7 + 0.5,
48.2 + i * 1e-6,
16.37 + i * 1e-6,
]
}
Loading