MySQL 优化的一环是要做索引,B-tree 索引要左侧优先匹配,在使用 sequelize 查询的时候,where 条件需要匹配索引来进行优化。 但是我最近发现个别的查询跟预想的不一样,没用按照自定义的查询条件顺序拼接 SQL。比如:
User 表 Model id, nickname, createTime, state
对应数据库的表结构 id, nickname, create_time, state
查询的代码片段:
await User.findAll({
attributes: ['id'],
where: {
id: {
$gt: 1000
},
createTime: moment().format('YYYY-MM-DD HH:mm:ss'),
nickname: '123123',
},
offset: 0,
limit: 20
})
await User.findAll({
attributes: ['id'],
where: {
id: {
$gt: 1000
},
nickname: '123123',
createTime: moment().format('YYYY-MM-DD HH:mm:ss'),
},
offset: 0,
limit: 20
})
很明显,查询条件里 nickname, createTime 是有先后顺序传入的, 但是打印的 sql 都是一样的:
打印 sql:
SELECT `id` FROM `user` AS `User` WHERE `User`.`id` > 1000 AND `User`.`nickname` = '123123' AND `User`.`create_time` = '2019-09-27 14:41:52' LIMIT 0, 20;
但是有些条件就可以按传入顺序拼接:
await User.findAll({
attributes: ['id'],
where: {
avatar: 'xx',
id: {
$gt: 1000
},
},
offset: 0,
limit: 20
})
// SQL
// SELECT `id` FROM `user` AS `User` WHERE `User`.`avatar` = 'xx' AND `User`.`id` > 1000 LIMIT 0, 20;
await User.findAll({
attributes: ['id'],
where: {
id: {
$gt: 1000
},
avatar: 'xx'
},
offset: 0,
limit: 20
})
// SELECT `id` FROM `user` AS `User` WHERE `User`.`id` > 1000 AND `User`.`avatar` = 'xx' LIMIT 0, 20;
求高人指点,提供点思路。
个人建议,不要使用智障mysql
@waitingsong 那用 excel ?
debug 找到问题了,解决办法,createTime 查询条件改成 create_time。
sequelize 在最后生成 sql 之前,会对传入的 where 条件和跟数据库的 column 进行比对,比如 filed: createTime, column: create_time
这种情况,sequelize 会在 model.js 调用 util.js 的 mapOptionFieldNames 方法进行替换,导致了 where 条件的混乱。
简单说一下出现问题的关键地方:
- 原 where 条件 {id, createTime, state}
- 添加替换后条件 {id, createTime, state, create_time}
- 删除原有条件 {id, state, create_time}
完美打乱,真坑。
@Sirormy 商业的 mssql, oracle,免费的 pgsql 。 皆由查询规划器根据查询条件以及库表统计信息来分析并决定采用相关索引。 即 SQL 查询条件位置顺序并不会影响查询计划。
绝大多数所谓 mysql 优化技术或者优化经验本质上是源于mysql天生弱智,后期发育不良所产生的补救措施。
@waitingsong 确实有些场景下优化方案解决了其他厂商并不存在的问题,MongoDB 的索引机制也得这样写,其他的没用过,不多评论。
@Sirormy 多数(数据)不值钱项目用啥技术(数据库)倒是无所谓的。 BATJ 除外,他们用啥都行,因为它们有能力把任何玩具改装成利器。