benchmarks/nodejs/index.js (306 lines of code) (raw):
const {Spanner} = require('@google-cloud/spanner');
const { Pool } = require('pg');
const projectId = 'spanner-pg-preview-internal';
const instanceId = 'europe-north1';
const databaseId = 'knut-test-db';
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
async function test() {
// Creates a Spanner client
const spanner = new Spanner({projectId});
// Creates a PG client pool.
const pool = new Pool({
user: 'user',
host: '/tmp',
database: 'knut-test-db',
password: 'password',
port: 5432,
max: 400,
});
// Gets a reference to a Cloud Spanner instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);
// Make sure the session pools have been initialized.
await database.run('select 1');
await pool.query('select 1');
await spannerSelectRowsSequentially(database, 100);
await spannerSelectMultipleRows(database, 20, 500);
await spannerSelectAndUpdateRows(database, 20, 5);
await spannerSelectRowsInParallel(database, 1000);
await spannerSelectMultipleRowsInParallel(database, 200, 500);
await spannerSelectAndUpdateRowsInParallel(database, 200, 5);
await pgSelectRowsSequentially(pool, 100);
await pgSelectMultipleRows(pool, 20, 500);
await pgSelectAndUpdateRows(pool, 20, 5);
await pgSelectRowsInParallel(pool, 1000);
await pgSelectMultipleRowsInParallel(pool, 200, 500);
await pgSelectAndUpdateRowsInParallel(pool, 200, 5);
await database.close();
await pool.end();
}
async function spannerSelectRowsSequentially(database, numQueries) {
console.log(`Selecting ${numQueries} rows sequentially`);
const start = new Date();
for (let i = 0; i < numQueries; i++) {
const query = {
sql: 'SELECT * FROM all_types WHERE col_bigint=$1',
params: {
p1: getRandomInt(5000000),
},
};
await database.run(query);
process.stdout.write('.');
}
process.stdout.write('\n');
const end = new Date();
const elapsed = end - start;
console.log(`Execution time for selecting ${numQueries} rows sequentially: ${elapsed}ms`);
console.log(`Avg execution time: ${elapsed/numQueries}ms`);
}
async function spannerSelectRowsInParallel(database, numQueries) {
console.log(`Selecting ${numQueries} rows in parallel`);
const start = new Date();
const promises = [];
for (let i = 0; i < numQueries; i++) {
const query = {
sql: 'SELECT * FROM all_types WHERE col_bigint=$1',
params: {
p1: getRandomInt(5000000),
},
};
promises.push(database.run(query));
process.stdout.write('.');
}
process.stdout.write('\n');
console.log("Waiting for queries to finish");
const allRows = await Promise.all(promises);
allRows.forEach(rows => {
if (rows[0].length < 0 || rows[0].length > 1) {
console.log(`Unexpected row count: ${rows[0].length}`);
}
});
const end = new Date();
const elapsed = end - start;
console.log(`Execution time for selecting ${numQueries} rows in parallel: ${elapsed}ms`);
console.log(`Avg execution time: ${elapsed/numQueries}ms`);
}
async function spannerSelectMultipleRows(database, numQueries, numRows) {
console.log(`Selecting ${numQueries} with each ${numRows} rows sequentially`);
const start = new Date();
for (let i = 0; i < numQueries; i++) {
const query = {
sql: `SELECT * FROM all_types WHERE col_bigint>$1 LIMIT ${numRows}`,
params: {
p1: getRandomInt(5000000),
},
json: true,
};
await database.run(query);
process.stdout.write('.');
}
process.stdout.write('\n');
const end = new Date();
const elapsed = end - start;
console.log(`Execution time for executing ${numQueries} with ${numRows} rows each: ${elapsed}ms`);
console.log(`Avg execution time: ${elapsed/numQueries}ms`);
}
async function spannerSelectMultipleRowsInParallel(database, numQueries, numRows) {
console.log(`Selecting ${numQueries} with each ${numRows} rows in parallel`);
const start = new Date();
const promises = [];
for (let i = 0; i < numQueries; i++) {
const query = {
sql: `SELECT * FROM all_types WHERE col_bigint>$1 LIMIT ${numRows}`,
params: {
p1: getRandomInt(5000000),
},
json: true,
};
promises.push(database.run(query));
process.stdout.write('.');
}
process.stdout.write('\n');
console.log("Waiting for queries to finish");
const allRows = await Promise.all(promises);
allRows.forEach(rows => {
if (rows[0].length < 0 || rows[0].length > numRows) {
console.log(`Unexpected row count: ${rows[0].length}`);
}
});
const end = new Date();
const elapsed = end - start;
console.log(`Execution time for executing ${numQueries} with ${numRows} rows each in parallel: ${elapsed}ms`);
console.log(`Avg execution time: ${elapsed/numQueries}ms`);
}
async function spannerSelectAndUpdateRows(database, numTransactions, numRowsPerTx) {
console.log(`Executing ${numTransactions} with each ${numRowsPerTx} rows per transaction`);
const start = new Date();
for (let i = 0; i < numTransactions; i++) {
await database.runTransactionAsync(selectAndUpdate);
process.stdout.write('.');
}
process.stdout.write('\n');
const end = new Date();
const elapsed = end - start;
console.log(`Execution time executing ${numTransactions} with ${numRowsPerTx} rows each: ${elapsed}ms`);
console.log(`Avg execution time: ${elapsed/numTransactions}ms`);
}
async function spannerSelectAndUpdateRowsInParallel(database, numTransactions, numRowsPerTx) {
console.log(`Executing ${numTransactions} with each ${numRowsPerTx} rows per transaction in parallel`);
const start = new Date();
const promises = [];
for (let i = 0; i < numTransactions; i++) {
promises.push(database.runTransactionAsync(selectAndUpdate));
process.stdout.write('.');
}
process.stdout.write('\n');
console.log("Waiting for transactions to finish");
await Promise.all(promises);
const end = new Date();
const elapsed = end - start;
console.log(`Execution time executing ${numTransactions} with ${numRowsPerTx} rows each: ${elapsed}ms`);
console.log(`Avg execution time: ${elapsed/numTransactions}ms`);
}
async function selectAndUpdate(tx) {
const query = {
sql: 'SELECT * FROM all_types WHERE col_bigint=$1',
params: {
p1: getRandomInt(5000000),
},
json: true,
};
const [rows] = await tx.run(query);
if (rows.length === 1) {
rows[0].col_float8 = Math.random();
const update = {
sql: 'UPDATE all_types SET col_float8=$1 WHERE col_bigint=$2',
params: {
p1: rows[0].col_float8,
p2: rows[0].col_bigint,
},
}
const [rowCount] = await tx.runUpdate(update);
if (rowCount !== 1) {
console.error(`Unexpected update count: ${rowCount}`);
}
}
await tx.commit();
}
async function pgSelectRowsSequentially(pool, numQueries) {
console.log(`PG: Selecting ${numQueries} rows sequentially`);
const start = new Date();
for (let i = 0; i < numQueries; i++) {
await pool.query('SELECT * FROM all_types WHERE col_bigint=$1', [getRandomInt(5000000)]);
process.stdout.write('.');
}
process.stdout.write('\n');
const end = new Date();
const elapsed = end - start;
console.log(`PG: Execution time for selecting ${numQueries} rows sequentially: ${elapsed}ms`);
console.log(`PG: Avg execution time: ${elapsed/numQueries}ms`);
}
async function pgSelectRowsInParallel(pool, numQueries) {
console.log(`PG: Selecting ${numQueries} rows in parallel`);
const start = new Date();
const promises = [];
for (let i = 0; i < numQueries; i++) {
promises.push(pool.query('SELECT * FROM all_types WHERE col_bigint=$1', [getRandomInt(5000000)]));
process.stdout.write('.');
}
process.stdout.write('\n');
console.log("Waiting for queries to finish");
const allRows = await Promise.all(promises);
allRows.forEach(result => {
if (result.rows.length < 0 || result.rows.length > 1) {
console.log(`Unexpected row count: ${result.rows.length}`);
}
});
const end = new Date();
const elapsed = end - start;
console.log(`PG: Execution time for selecting ${numQueries} rows in parallel: ${elapsed}ms`);
console.log(`PG: Avg execution time: ${elapsed/numQueries}ms`);
}
async function pgSelectMultipleRows(pool, numQueries, numRows) {
console.log(`PG: Selecting ${numQueries} with each ${numRows} rows sequentially`);
const start = new Date();
for (let i = 0; i < numQueries; i++) {
const sql = `SELECT * FROM all_types WHERE col_bigint>$1 LIMIT ${numRows}`;
await pool.query(sql, [getRandomInt(5000000)]);
process.stdout.write('.');
}
process.stdout.write('\n');
const end = new Date();
const elapsed = end - start;
console.log(`PG: Execution time for executing ${numQueries} with ${numRows} rows each: ${elapsed}ms`);
console.log(`PG: Avg execution time: ${elapsed/numQueries}ms`);
}
async function pgSelectMultipleRowsInParallel(pool, numQueries, numRows) {
console.log(`PG: Selecting ${numQueries} with each ${numRows} rows in parallel`);
const start = new Date();
const promises = [];
for (let i = 0; i < numQueries; i++) {
const sql = `SELECT * FROM all_types WHERE col_bigint>$1 LIMIT ${numRows}`;
promises.push(pool.query(sql, [getRandomInt(5000000)]));
process.stdout.write('.');
}
console.log("Waiting for queries to finish");
const allResults = await Promise.all(promises);
allResults.forEach(result => {
if (result.rows.length < 0 || result.rows.length > numRows) {
console.log(`Unexpected row count: ${result.rows.length}`);
}
});
const end = new Date();
const elapsed = end - start;
console.log(`PG: Execution time for executing ${numQueries} with ${numRows} rows each: ${elapsed}ms`);
console.log(`PG: Avg execution time: ${elapsed/numQueries}ms`);
}
async function pgSelectAndUpdateRows(pool, numTransactions, numRowsPerTx) {
console.log(`PG: Executing ${numTransactions} with each ${numRowsPerTx} rows per transaction`);
const start = new Date();
for (let i = 0; i < numTransactions; i++) {
await pgRunTransaction(pool);
process.stdout.write('.');
}
process.stdout.write('\n');
const end = new Date();
const elapsed = end - start;
console.log(`PG: Execution time executing ${numTransactions} with ${numRowsPerTx} rows each: ${elapsed}ms`);
console.log(`PG: Avg execution time: ${elapsed/numTransactions}ms`);
}
async function pgSelectAndUpdateRowsInParallel(pool, numTransactions, numRowsPerTx) {
console.log(`PG: Executing ${numTransactions} with each ${numRowsPerTx} rows per transaction`);
const start = new Date();
const promises = [];
for (let i = 0; i < numTransactions; i++) {
promises.push(pgRunTransaction(pool));
process.stdout.write('.');
}
process.stdout.write('\n');
console.log("Waiting for transactions to finish");
await Promise.all(promises);
const end = new Date();
const elapsed = end - start;
console.log(`PG: Execution time executing ${numTransactions} with ${numRowsPerTx} rows each: ${elapsed}ms`);
console.log(`PG: Avg execution time: ${elapsed/numTransactions}ms`);
}
async function pgRunTransaction(pool) {
const client = await pool.connect()
try {
await client.query('BEGIN');
const selectResult = await client.query('SELECT * FROM all_types WHERE col_bigint=$1', [getRandomInt(5000000)]);
if (selectResult.rows.length === 1) {
const updateResult = await client.query('UPDATE all_types SET col_float8=$1 WHERE col_bigint=$2', [
Math.random(),
selectResult.rows[0].col_bigint,
]);
if (updateResult.rowCount !== 1) {
console.error(`Unexpected update count: ${updateResult.rowCount}`);
}
}
await client.query('COMMIT')
} catch (e) {
await client.query('ROLLBACK')
throw e
} finally {
client.release()
}
}
test().then(() => console.log('Finished'));