Skip to content

Commit

Permalink
feat: support setting optimizerStatisticsPackage
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 Aug 27, 2020
1 parent 9994ec4 commit d8945eb
Show file tree
Hide file tree
Showing 3 changed files with 64 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 @@ -375,6 +375,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
76 changes: 51 additions & 25 deletions test/spanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,8 @@ 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 @@ -823,20 +824,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 @@ -846,14 +855,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 @@ -864,14 +874,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 @@ -882,14 +893,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 @@ -900,6 +912,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 @@ -916,6 +930,7 @@ 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 @@ -928,13 +943,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 @@ -945,10 +961,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 @@ -961,9 +978,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 @@ -974,7 +992,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 @@ -989,9 +1007,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 @@ -1001,11 +1020,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 @@ -1017,7 +1037,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 @@ -1032,9 +1052,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 @@ -1044,11 +1065,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 @@ -1060,7 +1082,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 @@ -1076,9 +1098,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 @@ -1089,11 +1112,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 @@ -1104,19 +1128,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 @@ -1127,7 +1153,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 @@ -1139,7 +1165,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 @@ -1151,7 +1177,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 d8945eb

Please sign in to comment.