查询多个列的集合匹配的更有效的方式



基本上我想做的是Sequelize等同于这个问题:

查询这些数据的更有效的方法?

我的用例与上面的问题有点不同,更麻烦。特别是:

  1. 不像原来的问题,我使用MySQL。
  2. 我的案例可能不仅仅是一对值,而是一组多达4个不同的值(每组值的数量不固定),这都要归功于我公司的完美的数据库
  3. 设置的最大数量不仅限于~100套。我可以看到这很容易超过2000套。(这是我最关心的)

这个查询是一个已经相当复杂的函数的一部分。我已经尽可能地把它剪短了,但还是花了不少时间。据我估计,这个查询在整个函数运行期间将被触发5到7次。我尝试了以下操作:

  • 将处理过的搜索集塞进[Op.or]的传统方法会触发一个非常长的查询,这可能超过MySQL的查询行限制(我不允许改变这一点)。
  • 逐项查询是可靠的,但速度较慢。

main函数现在大约在1分钟内运行(注意,这是我使用较小的数据集进行测试,实际运行时间很容易是4-5倍),我认为这是不可接受的,因为它每天被调用多次。我也不能大量修改数据库本身,因为它是一个遗留数据库,也被其他应用程序使用。如果原来的数据库设计得当,我们就不会走到这一步,但是唉,我只能尽力而为。

任何帮助都将是非常感激的。

在MySQL中,你可以在WHERE子句中使用元组,你可以用ANY_VALUE(attribute name)填充缺失的值来匹配任何东西。

SELECT * FROM Employees 
WHERE (name, age, dept, salary) IN (
('Alice', 40, ANY_VALUE(dept), ANY_VALUE(salary)),
('Bob', ANY_VALUE(age), 'Tech', 120),
('Mike', 25, 'HR', ANY_VALUE(salary))
)

我用100k的数据和1k的条件进行了测试,查询在我的笔记本电脑上返回了2.954s

========================================================

如果始终有4个值,不需要ANY_VALUE,则可以用最少的literal编写Sequelize。

const criteria = [
['Alice', 40, 'Tech', 120],
['Bob', 30, 'Tech', 120],
['Mike', 25, 'HR', 120]
];
const result = await db.Employee.findAll({
where: Sequelize.where(Sequelize.literal('(name, age, dept, salary)'), Op.in, [criteria])
});

但是,在您的示例中,该集合不能保证具有所有4个值,因此需要ANY_VALUE。不幸的是,我不能在Sequelize.where中使用Sequelize.fn('ANY_VALUE', 'name'),因为它试图转义它,它不能转义。

因此,Sequelize.where的第三个参数也需要替换为literal。在这一点上,代码主要是literal,我不认为仅仅使用Sequelize.query有任何区别,除非你使用许多其他选项,如偏移量,限制,属性……可以使Sequelize的查询生成器受益。

const result = await db.sequelize.query(`
SELECT * FROM Employees WHERE (name, age, dept, salary) IN (${constructedCriteria})`, 
{ type: Sequelize.QueryTypes.SELECT } // This will let Sequelize to format the response as in `findAll` function.
);

的一些想法。

  • >1k标准的用例是什么?所有的1k个标准都是不同的吗?
  • 也许这个场景更适合像ElasticSearch这样的搜索引擎?(如果您的情况灵活)

最新更新