【问题标题】:sails.js bluebird promise chaining multiple query slowsails.js 蓝鸟承诺链接多个查询缓慢
【发布时间】:2016-02-04 18:39:49
【问题描述】:

我是 node.js/sails.js 的新手。我听说 node.js 非常快。但我的表现很差。在这里,我使用了 bluebird 作为 promise。基本上我想重构它,这样它会更快。在这里,我正在执行四种不同的查询来获取产品详细信息(名称、型号、描述等)、产品附加图像、产品选项和每个选项的详细信息。

我想知道如何将这四个查询拆分为四个不同的方法或函数,以便我以后可以重用它们,而且当我调用 getgetProductdetails 时,这将调用所有四个查询并更快地获得最终结果。请帮助我。我被困住了。非常感谢。

// api/model/product.js
    getProductDetails:function(product_id){
        return new Promise(function(resolve, reject) {
            var product={},options=[];
            //details
          Product.query("select * from product p , product_description pd where p.product_id="+product_id+" and pd.product_id= p.product_id and pd.language_id=1",function(error, details) {
            //images    
            Product.query("SELECT * FROM product_image WHERE product_id = "+product_id+" ORDER BY sort_order ASC",function(error, images) { 

            //options   
            Product.query("SELECT * FROM product_option po LEFT JOIN `option` o ON (po.option_id = o.option_id) LEFT JOIN option_description od ON (o.option_id = od.option_id) WHERE po.product_id = "+product_id+" AND od.language_id = '1' ORDER BY o.sort_order",function(error, options) {
                    options.forEach(function (item) {
                                //options value
                              Product.query("SELECT * FROM product_option_value pov LEFT JOIN option_value ov ON (pov.option_value_id = ov.option_value_id) LEFT JOIN option_value_description ovd ON (ov.option_value_id = ovd.option_value_id) WHERE pov.product_id = "+product_id+" AND pov.product_option_id = "+item.product_option_id+" AND ovd.language_id = '1' ORDER BY ov.sort_order",function(error,option_value){
                                    options.push({options: item, option_value: option_value});
                                });
                        });//foreach option
                product={details:details[0], options: options, images:images};
                resolve(product);
            }); 

        });

        });

        }); 
    }   

【问题讨论】:

  • 您正在运行多少个查询(以及您有多少数据)?那些没有事务的嵌套循环查询应该会破坏任何东西的性能。
  • 好吧,我可以理解数据量和查询会降低性能。但是如果我在 php 中做同样的事情,它非常快,但不是在这里。所以我想知道如何将这些查询拆分为不同的方法/函数。你有答案吗?
  • 我会开始优化您的查询,这样您就不会在紧密循环中调用非事务左连接。
  • 我不知道如何在 node.js 中做到这一点

标签: javascript node.js promise sails.js bluebird


【解决方案1】:

对于某些工作负载和模式,节点“快速”。它的很多速度来自它处理 IO 和网络任务(例如数据库查询)的方式,这增加了它处理规模的能力。 [如果你有兴趣阅读更多关于它及其工作原理的信息,请阅读事件循环 - here 是一篇好文章]

就改进您提供的代码而言 - 我假设您使用的是 Bluebird 并安装了 Underscore.js 以使其稍微整洁一些。出于安全原因,我强烈建议切换到 ORM 或至少确保您转义 SQL 查询中的信息。 Node 速度很快,但不能解决注入问题:)

我已经重构了您的代码,以便请求可以并行执行,这应该有助于通过利用任何其他语言的并发性来加速您的代码。我已经使用了 Promise 并且还利用了 bluebird promisify all 系统,这样您就不需要创建 Promise。

var promisifiedProduct = Promise.promisifyAll(Product)
var _ = require('underscore')

getProductDetails: function(product_id) {

    var details_retriever = promisifiedProduct.queryAsync("select * from product p, product_description pd where p.product_id=" + product_id + " and pd.product_id= p.product_id and pd.language_id=1")

    var images_retriever = promisifiedProduct.queryAsync("SELECT * FROM product_image WHERE product_id = " + product_id + " ORDER BY sort_order ASC")

    var options_retriever = promisifiedProduct.queryAsync("SELECT * FROM product_option po LEFT JOIN `option` o ON (po.option_id = o.option_id) LEFT JOIN option_description od ON (o.option_id = od.option_id) WHERE po.product_id = " + product_id + " AND od.language_id = '1' ORDER BY o.sort_order")

    // Iterate over each option for some additional information
    var sub_options_retriever = options_retriever.then(function(options) {

        // Map the options to a Promise that will resolve to the value
        var sub_option_retrievers = _.map(options, function (option) {

            // Return a Promise that resolves to the desired object
            return  promisifiedProduct.queryAsync("SELECT * FROM product_option_value pov LEFT JOIN option_value ov ON (pov.option_value_id = ov.option_value_id) LEFT JOIN option_value_description ovd ON (ov.option_value_id = ovd.option_value_id) WHERE pov.product_id = " + product_id + " AND pov.product_option_id = " + option.product_option_id + " AND ovd.language_id = '1' ORDER BY ov.sort_order")
                .then(function(sub_options) {

                    return {
                        options: option, 
                        option_value: sub_options
                    }

                })

        })

        // Concurrently retrieve the sub options
        return Promisify.all(sub_option_retrievers)

    })

    // Wait for all the information to be retrieved
    var retriever = Promisify.all([details_retriever, images_retriever, options_retriever, sub_option_retriever])

    var result_formatter = retriever.then(function(results) {

        // Create a scope level variable for options so we are not mutating a provided argument
        var options = results[2]

        // Add each sub_option into options - Not sure why?
        var formatted_options = _.forEach(result[3], function(sub_option) {
            options.push(sub_option)
        })

        return {
            details: results[0][0],
            options: formatted_options, 
            images: results[1]
        }
    })

    return result_formatter
}

我没有测试代码或仔细检查任何功能,所以它可能需要一些调整,但应该很好!

【讨论】:

  • 上述 cmets 中关于 SQL 查询的担忧是有效的,您应该考虑优化它们 - 但我不是在面向 SQL 的基础上工作。如果您的性能损失是基于 SQL 的,那么这是一个不同的问题。
  • 出现错误; var promisifiedProduct = Promise.promisifyAll(Product);产品未定义。我认为 Product 应该被替换。
  • @PritamParua Product 应该等于 Product 在您的原始示例中等于什么。由于示例中没有定义它,所以我看不到它是什么。
  • 我确实忘记用 promisifiedProduct 替换原来的 Product 调用 - 试试新的更新示例,看看效果如何。
猜你喜欢
  • 1970-01-01
  • 2015-09-05
  • 2014-02-11
  • 1970-01-01
  • 1970-01-01
  • 2015-08-24
  • 1970-01-01
  • 1970-01-01
  • 2014-02-13
相关资源
最近更新 更多