Skip to content

Commit

Permalink
feat: support setting optimizerStatisticsPackage (#1225)
Browse files Browse the repository at this point in the history
`optimizerStatisticsPackage` can be set in `QueryOptions` when running Cloud Spanner queries.
    
Can be configured through the following mechanisms:    
1. Through the `SPANNER_OPTIMIZER_STATISTICS_PACKAGE` environment variable.
1. At `Database` level using `spanner.instance('instance-name').database('database-name', sessionPoolOptions, queryOptions)`.
1. At query level using `ExecuteSqlRequest.queryOptions`.
    
If the options are configured through multiple mechanisms then:    
1. Options set at an environment variable level will override options configured at the `Database` level.
1. Options set at a query-level will override options set at either the `Database` or environment variable level.
    
If no options are set, the optimizer statistics package will default to:    
1. The optimizer statistics package the database is pinned to in the backend.
1. If the database is not pinned to a specific statistics package, then the Cloud Spanner backend will use the "latest" version.
  • Loading branch information
skuruppu committed Jun 4, 2021
1 parent b18be4b commit dadc6dc
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 26 deletions.
10 changes: 9 additions & 1 deletion samples/queryoptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,14 @@ async function databaseWithQueryOptions(instanceId, databaseId, projectId) {

// Gets a reference to a Cloud Spanner instance and database
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId, {}, {optimizerVersion: '1'});
const database = instance.database(
databaseId,
{},
{
optimizerVersion: '1',
optimizerStatisticsPackage: 'auto_20191128_14_47_22UTC',
}
);

const query = {
sql: `SELECT AlbumId, AlbumTitle, MarketingBudget
Expand Down Expand Up @@ -90,6 +97,7 @@ async function queryWithQueryOptions(instanceId, databaseId, projectId) {
ORDER BY AlbumTitle`,
queryOptions: {
optimizerVersion: 'latest',
optimizerStatisticsPackage: 'latest',
},
};

Expand Down
4 changes: 4 additions & 0 deletions src/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,10 @@ class Database extends common.GrpcServiceObject {
if (process.env.SPANNER_OPTIMIZER_VERSION) {
options.optimizerVersion = process.env.SPANNER_OPTIMIZER_VERSION;
}
if (process.env.SPANNER_OPTIMIZER_STATISTICS_PACKAGE) {
options.optimizerStatisticsPackage =
process.env.SPANNER_OPTIMIZER_STATISTICS_PACKAGE;
}
return options;
}

Expand Down
79 changes: 54 additions & 25 deletions test/spanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,10 @@ describe('Spanner with mock server', () => {

describe('queryOptions', () => {
/** Common verify method for QueryOptions tests. */
function verifyQueryOptions(optimizerVersion: string) {
function verifyQueryOptions(
optimizerVersion: string,
optimizerStatisticsPackage: string
) {
const request = spannerMock.getRequests().find(val => {
return (val as v1.ExecuteSqlRequest).sql;
}) as v1.ExecuteSqlRequest;
Expand All @@ -957,20 +960,28 @@ describe('Spanner with mock server', () => {
request.queryOptions!.optimizerVersion,
optimizerVersion
);
assert.strictEqual(
request.queryOptions!.optimizerStatisticsPackage,
optimizerStatisticsPackage
);
}

describe('on request', () => {
const OPTIMIZER_VERSION = '100';
const OPTIMIZER_STATISTICS_PACKAGE = 'auto_20191128_14_47_22UTC';

it('database.run', async () => {
const query = {
sql: selectSql,
queryOptions: QueryOptions.create({
optimizerVersion: '100',
optimizerVersion: OPTIMIZER_VERSION,
optimizerStatisticsPackage: OPTIMIZER_STATISTICS_PACKAGE,
}),
} as ExecuteSqlRequest;
const database = newTestDatabase();
try {
await database.run(query);
verifyQueryOptions('100');
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
} finally {
await database.close();
}
Expand All @@ -980,14 +991,15 @@ describe('Spanner with mock server', () => {
const query = {
sql: selectSql,
queryOptions: QueryOptions.create({
optimizerVersion: '100',
optimizerVersion: OPTIMIZER_VERSION,
optimizerStatisticsPackage: OPTIMIZER_STATISTICS_PACKAGE,
}),
} as ExecuteSqlRequest;
const database = newTestDatabase();
try {
const [snapshot] = await database.getSnapshot();
await snapshot.run(query);
verifyQueryOptions('100');
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await snapshot.end();
} finally {
await database.close();
Expand All @@ -998,14 +1010,15 @@ describe('Spanner with mock server', () => {
const query = {
sql: selectSql,
queryOptions: QueryOptions.create({
optimizerVersion: '100',
optimizerVersion: OPTIMIZER_VERSION,
optimizerStatisticsPackage: OPTIMIZER_STATISTICS_PACKAGE,
}),
} as ExecuteSqlRequest;
const database = newTestDatabase();
database.runTransaction(async (err, transaction) => {
assert.ifError(err);
await transaction!.run(query);
verifyQueryOptions('100');
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await transaction!.commit();
await database.close();
done();
Expand All @@ -1016,14 +1029,15 @@ describe('Spanner with mock server', () => {
const query = {
sql: selectSql,
queryOptions: QueryOptions.create({
optimizerVersion: '100',
optimizerVersion: OPTIMIZER_VERSION,
optimizerStatisticsPackage: OPTIMIZER_STATISTICS_PACKAGE,
}),
} as ExecuteSqlRequest;
const database = newTestDatabase();
try {
await database.runTransactionAsync(async transaction => {
await transaction.run(query);
verifyQueryOptions('100');
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await transaction.commit();
});
} finally {
Expand All @@ -1034,6 +1048,8 @@ describe('Spanner with mock server', () => {

describe('with environment variable', () => {
const OPTIMIZER_VERSION = '20';
const OPTIMIZER_STATISTICS_PACKAGE = 'auto_20191128_14_47_22UTC';

let spannerWithEnvVar: Spanner;
let instanceWithEnvVar: Instance;

Expand All @@ -1050,6 +1066,8 @@ describe('Spanner with mock server', () => {

before(() => {
process.env.SPANNER_OPTIMIZER_VERSION = OPTIMIZER_VERSION;
process.env.SPANNER_OPTIMIZER_STATISTICS_PACKAGE =
OPTIMIZER_STATISTICS_PACKAGE;
spannerWithEnvVar = new Spanner({
projectId: 'fake-project-id',
servicePath: 'localhost',
Expand All @@ -1062,13 +1080,14 @@ describe('Spanner with mock server', () => {

after(() => {
delete process.env.SPANNER_OPTIMIZER_VERSION;
delete process.env.SPANNER_OPTIMIZER_STATISTICS_PACKAGE;
});

it('database.run', async () => {
const database = newTestDatabase();
try {
await database.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
} finally {
await database.close();
}
Expand All @@ -1079,10 +1098,11 @@ describe('Spanner with mock server', () => {
// as they are overridden by the environment variable.
const database = newTestDatabase(undefined, {
optimizerVersion: 'version-in-db-opts',
optimizerStatisticsPackage: 'stats-package-in-db-opts',
});
try {
await database.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
} finally {
await database.close();
}
Expand All @@ -1095,9 +1115,10 @@ describe('Spanner with mock server', () => {
sql: selectSql,
queryOptions: {
optimizerVersion: 'version-on-query',
optimizerStatisticsPackage: 'stats-package-on-query',
},
});
verifyQueryOptions('version-on-query');
verifyQueryOptions('version-on-query', 'stats-package-on-query');
} finally {
await database.close();
}
Expand All @@ -1108,7 +1129,7 @@ describe('Spanner with mock server', () => {
try {
const [snapshot] = await database.getSnapshot();
await snapshot.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await snapshot.end();
} finally {
await database.close();
Expand All @@ -1123,9 +1144,10 @@ describe('Spanner with mock server', () => {
sql: selectSql,
queryOptions: {
optimizerVersion: 'version-on-query',
optimizerStatisticsPackage: 'stats-package-on-query',
},
});
verifyQueryOptions('version-on-query');
verifyQueryOptions('version-on-query', 'stats-package-on-query');
await snapshot.end();
} finally {
await database.close();
Expand All @@ -1135,11 +1157,12 @@ describe('Spanner with mock server', () => {
it('snapshot.run with database-with-query-options', async () => {
const database = newTestDatabase(undefined, {
optimizerVersion: 'version-in-db-opts',
optimizerStatisticsPackage: 'stats-package-in-db-opts',
});
try {
const [snapshot] = await database.getSnapshot();
await snapshot.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await snapshot.end();
} finally {
await database.close();
Expand All @@ -1151,7 +1174,7 @@ describe('Spanner with mock server', () => {
database.runTransaction(async (err, transaction) => {
assert.ifError(err);
await transaction!.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await transaction!.commit();
await database.close();
done();
Expand All @@ -1166,9 +1189,10 @@ describe('Spanner with mock server', () => {
sql: selectSql,
queryOptions: {
optimizerVersion: 'version-on-query',
optimizerStatisticsPackage: 'stats-package-on-query',
},
});
verifyQueryOptions('version-on-query');
verifyQueryOptions('version-on-query', 'stats-package-on-query');
await transaction!.commit();
await database.close();
done();
Expand All @@ -1178,11 +1202,12 @@ describe('Spanner with mock server', () => {
it('transaction.run with database-with-query-options', done => {
const database = newTestDatabase(undefined, {
optimizerVersion: 'version-in-db-opts',
optimizerStatisticsPackage: 'stats-package-in-db-opts',
});
database.runTransaction(async (err, transaction) => {
assert.ifError(err);
await transaction!.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await transaction!.commit();
await database.close();
done();
Expand All @@ -1194,7 +1219,7 @@ describe('Spanner with mock server', () => {
try {
await database.runTransactionAsync(async transaction => {
await transaction.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await transaction.commit();
});
} finally {
Expand All @@ -1210,9 +1235,10 @@ describe('Spanner with mock server', () => {
sql: selectSql,
queryOptions: {
optimizerVersion: 'version-on-query',
optimizerStatisticsPackage: 'stats-package-on-query',
},
});
verifyQueryOptions('version-on-query');
verifyQueryOptions('version-on-query', 'stats-package-on-query');
await transaction.commit();
});
} finally {
Expand All @@ -1223,11 +1249,12 @@ describe('Spanner with mock server', () => {
it('async transaction.run with database-with-query-options', async () => {
const database = newTestDatabase(undefined, {
optimizerVersion: 'version-in-db-opts',
optimizerStatisticsPackage: 'stats-package-in-db-opts',
});
try {
await database.runTransactionAsync(async transaction => {
await transaction.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await transaction.commit();
});
} finally {
Expand All @@ -1238,19 +1265,21 @@ describe('Spanner with mock server', () => {

describe('on database options', () => {
const OPTIMIZER_VERSION = '40';
const OPTIMIZER_STATISTICS_PACKAGE = 'auto_20191128_14_47_22UTC';

// Request a database with default query options.
function newTestDatabase(options?: SessionPoolOptions): Database {
return instance.database(`database-${dbCounter++}`, options, {
optimizerVersion: OPTIMIZER_VERSION,
optimizerStatisticsPackage: OPTIMIZER_STATISTICS_PACKAGE,
} as IQueryOptions);
}

it('database.run', async () => {
const database = newTestDatabase();
try {
await database.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
} finally {
await database.close();
}
Expand All @@ -1261,7 +1290,7 @@ describe('Spanner with mock server', () => {
try {
const [snapshot] = await database.getSnapshot();
await snapshot.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await snapshot.end();
} finally {
await database.close();
Expand All @@ -1273,7 +1302,7 @@ describe('Spanner with mock server', () => {
database.runTransaction(async (err, transaction) => {
assert.ifError(err);
await transaction!.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await transaction!.commit();
await database.close();
done();
Expand All @@ -1285,7 +1314,7 @@ describe('Spanner with mock server', () => {
try {
await database.runTransactionAsync(async transaction => {
await transaction.run(selectSql);
verifyQueryOptions(OPTIMIZER_VERSION);
verifyQueryOptions(OPTIMIZER_VERSION, OPTIMIZER_STATISTICS_PACKAGE);
await transaction.commit();
});
} finally {
Expand Down

0 comments on commit dadc6dc

Please sign in to comment.