不要怂,就是干,撸起袖子干!

Commit 720f7ec9 by Jonathan Hoyt Committed by Sushant

feat(mysql): indexHints support (#10756)

1 parent f4a46dc1
......@@ -493,3 +493,35 @@ Project.findAll({
// this will generate the SQL 'WITH (NOLOCK)'
})
```
## Index Hints
`indexHints` can be used to optionally pass index hints when using mysql. The hint type must be a value from `Sequelize.IndexHints` and the values should reference existing indexes.
Index hints [override the default behavior of the mysql query optimizer](https://dev.mysql.com/doc/refman/5.7/en/index-hints.html).
```js
Project.findAll({
indexHints: [
{ type: IndexHints.USE, values: ['index_project_on_name'] }
],
where: {
id: {
[Op.gt]: 623
},
name: {
[Op.like]: 'Foo %'
}
}
})
```
Will generate a mysql query that looks like this:
```sql
SELECT * FROM Project USE INDEX (index_project_on_name) WHERE name LIKE 'FOO %' AND id > 623;
```
`Sequelize.IndexHints` includes `USE`, `FORCE`, and `IGNORE`.
See [Issue #9421](https://github.com/sequelize/sequelize/issues/9421) for the original API proposal.
......@@ -16,6 +16,7 @@ const BelongsToMany = require('../../associations/belongs-to-many');
const HasMany = require('../../associations/has-many');
const Op = require('../../operators');
const sequelizeError = require('../../errors');
const { IndexHints } = require('../../index-hints');
const QuoteHelper = require('./query-generator/helpers/quote');
......@@ -1906,6 +1907,14 @@ class QueryGenerator {
fragment += ` AS ${mainTableAs}`;
}
if (options.indexHints && this._dialect.supports.indexHints) {
for (const hint of options.indexHints) {
if (IndexHints[hint.type]) {
fragment += ` ${IndexHints[hint.type]} INDEX (${hint.values.map(indexName => this.quoteIdentifiers(indexName)).join(',')})`;
}
}
}
return fragment;
}
......
......@@ -40,6 +40,7 @@ MysqlDialect.prototype.supports = _.merge(_.cloneDeep(AbstractDialect.prototype.
check: false
},
indexViaAlter: true,
indexHints: true,
NUMERIC: true,
GEOMETRY: true,
JSON: true,
......
'use strict';
/**
* An enum of index hints to be used in mysql for querying with index hints
*
* @property USE
* @property FORCE
* @property IGNORE
*/
exports.IndexHints = { // eslint-disable-line
USE: 'USE',
FORCE: 'FORCE',
IGNORE: 'IGNORE'
};
......@@ -6,6 +6,7 @@ const chai = require('chai'),
dialect = Support.getTestDialect(),
_ = require('lodash'),
Op = require('../../../../lib/operators'),
{ IndexHints } = require('../../../../lib/index-hints'),
QueryGenerator = require('../../../../lib/dialects/mysql/query-generator');
if (dialect === 'mysql') {
......@@ -709,11 +710,59 @@ if (dialect === 'mysql') {
expectation: 'DROP INDEX `user_foo_bar` ON `User`'
}
],
getForeignKeyQuery: [
{
arguments: ['User', 'email'],
expectation: "SELECT CONSTRAINT_NAME as constraint_name,CONSTRAINT_NAME as constraintName,CONSTRAINT_SCHEMA as constraintSchema,CONSTRAINT_SCHEMA as constraintCatalog,TABLE_NAME as tableName,TABLE_SCHEMA as tableSchema,TABLE_SCHEMA as tableCatalog,COLUMN_NAME as columnName,REFERENCED_TABLE_SCHEMA as referencedTableSchema,REFERENCED_TABLE_SCHEMA as referencedTableCatalog,REFERENCED_TABLE_NAME as referencedTableName,REFERENCED_COLUMN_NAME as referencedColumnName FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE (REFERENCED_TABLE_NAME = 'User' AND REFERENCED_COLUMN_NAME = 'email') OR (TABLE_NAME = 'User' AND COLUMN_NAME = 'email' AND REFERENCED_TABLE_NAME IS NOT NULL)"
}
],
selectFromTableFragment: [
{
arguments: [{}, null, ['*'], '`Project`'],
expectation: 'SELECT * FROM `Project`'
}, {
arguments: [
{ indexHints: [{ type: IndexHints.USE, values: ['index_project_on_name'] }] },
null,
['*'],
'`Project`'
],
expectation: 'SELECT * FROM `Project` USE INDEX (`index_project_on_name`)'
}, {
arguments: [
{ indexHints: [{ type: IndexHints.FORCE, values: ['index_project_on_name'] }] },
null,
['*'],
'`Project`'
],
expectation: 'SELECT * FROM `Project` FORCE INDEX (`index_project_on_name`)'
}, {
arguments: [
{ indexHints: [{ type: IndexHints.IGNORE, values: ['index_project_on_name'] }] },
null,
['*'],
'`Project`'
],
expectation: 'SELECT * FROM `Project` IGNORE INDEX (`index_project_on_name`)'
}, {
arguments: [
{ indexHints: [{ type: IndexHints.USE, values: ['index_project_on_name', 'index_project_on_name_and_foo'] }] },
null,
['*'],
'`Project`'
],
expectation: 'SELECT * FROM `Project` USE INDEX (`index_project_on_name`,`index_project_on_name_and_foo`)'
}, {
arguments: [
{ indexHints: [{ type: 'FOO', values: ['index_project_on_name'] }] },
null,
['*'],
'`Project`'
],
expectation: 'SELECT * FROM `Project`'
}
]
};
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!