因此,想象一下,我想检索一系列客户的所有订单。
下例中的arrayList
将具有一组客户ID。
此数组将传递到下面的get
方法中,并异步处理以获取数组中每个客户ID的订单。
在这里我迷路了。如何对数据库结果集进行分页并一次只从数据库中提取一小部分记录,而不必通过网络提取所有记录。
让我感到困惑的是异步特性以及我们不知道每个客户有多少个订单?那么如何一次有效地返回设置的页面大小?
service.js
function callToAnotherService(id) {
return new Promise((resolve, reject) => {
//calls service passing id
}
}
exports.get = arrayList => Promise.all(arrayList.map(callToAnotherService))
.then((result) => result);
答案 0 :(得分:2)
在MySQL中,有多种方法可以实现此目的。
您选择的方法取决于许多变量,例如您的实际分页方法(无论您是只想拥有“上一个”还是“下一个”按钮,或者实际上是要提供1 ... n的范围,其中n总计匹配记录数除以您的每页记录数);以及数据库设计,计划的增长,分区和/或分片,当前和预测的数据库负载,可能的硬查询限制(例如,如果您有多年的记录价值,则可能需要最终用户为查询选择一个合理的时间范围(上个月,过去3个月,去年等等),这样它们就不会因无限制和过于广泛的查询而使数据库超载。
如果您选择最后两个选项之一,则肯定需要知道找到的记录的总数。
正如我上面所说,实现同一目标的方法不止一种。必须根据情况进行选择。下面我将介绍一些简单的想法:
第一:
如果您的解决方案基于会话,并且您可以保留该会话,则可以使用temporary table,在其中只能选择 order_id (假设它是订单表中的主键)。 (可选)如果要获取每个客户的计数(或以其他方式过滤),还可以在订单表中的 order_id 旁边,将第二列添加为 customer_id 。 />
用最少的数据传播临时表后,您可以轻松地计算临时表中的行并基于该数字创建分页。
现在,当您开始显示页面时,只需选择这些行的子集(使用上面的 LIMIT 方法),然后从中 join 从中选择相应的记录(其余列)临时表 order_id 上的 orders 。
这有两个好处:
1)逐页浏览记录会很快,因为它不再查询(大概是)大订单表。
2)您不在以下位置使用汇总查询订单表,取决于记录的数量和设计,它们的性能会很差,并可能影响其他并发用户的性能。
请记住,最初的临时表创建会稍微慢一些。但是,如果不将临时表只限于基本列,那肯定会更加慢。
不过,建议您设置合理的最大硬限制(临时表记录的数量或某个时间范围) )进行初始查询
第二:
这是我的最爱,因为使用这种方法,我已经能够多次解决客户的大型数据库(或特定查询)性能问题。我们正在谈论将查询时间从50-55秒降低到毫秒。此方法尤其不受数据库可伸缩性下降的影响。
主要思想是您可以预先计算所有种类的汇总(例如产品的累计总和或每个客户的订单数等)。为此,您可以创建一个附加表来保存汇总(示例中每个客户的订单数)。
现在最重要的部分是:
您必须使用自定义数据库triggers,即您可以使用 ON INSERT 和 ON DELETE 触发器,该触发器将更新汇总表并增加/减少特定客户的订单数,具体取决于是否添加/删除了订单。触发器可以在更改触发表之前或之后触发,具体取决于您如何设置它们。
触发器实际上对数据库没有任何开销,因为它们对每个(插入/删除)的记录仅触发一次(除非您做一些愚蠢的操作,例如从某个大表中运行 COUNT(...)查询) ,这反而会完全破坏目标。)
我通常会更细化,例如每个客户每月的计数/总和,等等。
正确完成后,合计计数几乎不可能与实际记录不同步。如果您的应用程序启用了订单的customer_id更改,则可能还需要添加 ON UPDATE 触发器,因此订单的客户ID更改将自动反映在汇总表中。
当然,您可以使用更多方法。但是上面的这两个事实证明非常棒。这完全取决于情况...
我希望我的回答有点抽象,可以引导您走上正确的道路,因为我只能根据您提出的问题的少量信息来回答...
答案 1 :(得分:1)
在MySQL中,使用ORDER BY ... LIMIT 30, 10
跳过30行并获取10行。
更好地记住您离开的地方(比如说$ left_off),然后再做
WHERE id > $left_off
ORDER BY id
LIMIT 10
您抓到的最后一行是新的“ left_off”。
更好的是,但使用LIMIT 11
。然后,您可以显示10,但还可以发现是否还有更多(通过从SELECT
返回第11行来实现。