SequelizeJS 中的慢关联

Posted

技术标签:

【中文标题】SequelizeJS 中的慢关联【英文标题】:Slow associations in SequelizeJS 【发布时间】:2014-05-25 17:53:28 【问题描述】:

我正在尝试诊断使用 SequlizeJS 作为 ORM 的 Express 应用程序出现一些速度下降的原因。我有一个与其他 2 个模型有 2x hasMany 和 hasOne 关系的模型:

更新:我已经使用 classMethods#associate 函数在定义调用中建立了关联。

// Model1
classMethods: 
    associate: function(models) 
        Model1.hasMany(models.Model2);
        Model1.hasMany(models.Model3);
        Model1.hasOne(models.Model2, as: 'next', foreignKey: 'model2_next');
    


// Model2
classMethods: 
    associate: function(models) 
        Model2.belongsTo(models.Model1, foreignKey: 'model2_next');
    

如果我通过以下方式查询它们:

db.Model1.find(
    where:  /* Simple where statement */ ,
    include: [
        db.Model2,
        db.Model3,
         model: db.Model2, as: 'next' ,
    ]
).complete(function(err, data) 
    res.json(data);
);

响应可能需要 8-12 秒。但是,如果我单独查询 Model2 并使用 async 和 lodash 库手动合并它们:

async.parallel(
    model2: function(callback) 
        db.Model2.findAll(
            where:  /* Simple where statement */ 
        ).complete(callback)
    ,
    model1: function(callback) 
        db.Model1.find(
            where:  /* Simple where statement */ ,
            include: [
                db.Model3,
                 model: db.Model2, as: 'next' ,
            ]
        ).complete(callback);
    
, function(err, data) 
    var response = data.model1.values;
    response.Model2 = data.model2.map(function(Model2) return Model2.values );

    res.json(response);
)

需要 60-100 毫秒。

我尝试从 mysql 切换到 PostgreSQL,虽然 PostgreSQL 稍微快了一点,但也只是 2-3%!

是什么导致 Sequelize 花费的时间比拆分查询要长得多,有什么方法可以加快速度吗?

【问题讨论】:

你是如何关联对象的?解释sql查询,检查MYSQL是否使用索引? @ahipsa 谢谢,我已经用关联详细信息更新了问题。我将挖掘日志,看看是否可以尽快提取相关的 SQL 查询。关于索引; Sequelize 在 Model2 表中生成了一个 Model1Id - 我应该索引它吗? 我添加了关于索引的答案 表格有多少行?描述你的模型,它是什么?为什么它们是相关的?可能是数据库设计的问题。 注意:您可以在include 数组中使用 separate: true ,sequelize 将执行单独的查询并为您连接内存中的数据。 【参考方案1】:

将 :M 关系添加到包含时,Sequelize 会变慢。 :M 关系会导致您的 sql 结果中出现重复的行,因此我们必须花时间对其进行重复数据删除并将其解析为模型。

为了获得最佳性能,您可以将 :1 关系保留在包含中,但在单独的查询中执行 :M。

当然查询本身也可能很慢,但很可能是 Sequelize 开销的结果 - 尝试直接在数据库上运行查询。

(免责声明:Sequelize 核心开发者)

你运行的是什么版本?您报告的初始数字听起来很高,但我们在进行一些优化之前已经听说过这些数字,请尝试针对最新的 git master 进行测试。

我们一直致力于针对这些场景优化代码,但是将 20.000 行重复数据删除到 5.000 行将始终需要一些 cpu 周期。

【讨论】:

嗨@mick-hansen 感谢您抽出宝贵的时间...我看到您在问题跟踪器上的活动:) 正如我的问题中所建议的那样,我现在已经对查询进行了分段并手动将数据重新合并在一起.我使用的是 1.7 版,升级到 2.0(不稳定)会受到伤害吗? 升级到 2.0 有一些突破,但它们是更好的突破。性能和 API 方面。 好的,试试下面@ahipsa 的解决方案,也可以尝试升级,有没有升级指南或更新日志可以参考? 干杯米克,似乎在明显的地方哈哈 - 我完全没能找到它,呵呵:P @CharlieSchliesser 如果他们是 1:M 你现在可以使用seperate: true【参考方案2】:

在您的模型关联中,sequelizejs 不会创建索引

将foreignKeyConstraint: true 添加到所有关联。

Model1.hasMany(models.Model2, foreignKeyConstraint: true);
Model1.hasMany(models.Model3, foreignKeyConstraint: true);
Model1.hasOne(models.Model2, as: 'next', foreignKey: 'model2_next', foreignKeyConstraint: true);
Model2.belongsTo(models.Model1, foreignKey: 'model2_next', foreignKeyConstraint: true);

【讨论】:

嗨@ahipsa,感谢您的回答...这提高了性能,但不幸的是,每个查询仍然需要大约 4-5 秒。 也添加到第三个关联。表格有多少行?【参考方案3】:

对于您的 hasMany 包含(并在正确索引后),请考虑添加 separate: true,

它基本上是并行执行include 块,而不是顺序执行。

之后我的查询从 10 秒缩短到不到 200 毫秒:

include: [
    
        model: MyModel,
        as: 'myModels',
        separate: true, // does magic; only with .hasMany associations
    ,
]

文档:https://sequelize.org/master/class/lib/model.js~Model.html

【讨论】:

以上是关于SequelizeJS 中的慢关联的主要内容,如果未能解决你的问题,请参考以下文章

Sequelizejs 中的 .save 和 .create 有啥区别?

DESC 中的订单记录在 SequelizeJS 中不起作用

在 Sequelize 中限制延迟加载的关联

“用户未关联到提要!”续集

Sequelize - 是不是有双向关联?

Sequelize js如何获取关联模型的平均值(聚合)