让 Laravel Scout 导入提速 64 倍

下一个版本的 Laravel Scout 将会使你的模型查询速度提升64倍。

我使用null scout 驱动测试了一张包含 1,632,576条数据的表。消耗的时间从过去的29分57秒缩短到了28秒。 ^[返回原文]^

你能在这里 查看提交的 pull request.

这篇文章解释了为什么代码中的这个更改会带来这么大的变化。这是我在我自己的 Laravel 应用中用来加速存在问题的查询的一个技巧。一旦你理解了它的原理,我打赌你会找到一种新的优化你的应用的方式。

背景

默认情况下, Scout 会检索数据库中的每一行。为了保持内存使用的合理性,它使用 chunk 方法 一次只取几百行。

chunk 方法为你的查询添加了限制和偏移量,像这样:

select * from `users` order by `id` asc limit 500 offset 500;

要获取下一页,偏移量会递增。

select * from `users` order by `id` asc limit 500 offset 1000;

首先这很好用,这个查询大约只需要大约一毫秒,但你走的越远,它就越慢。

一旦偏移量达到了 1,000,000 ,查询速度就会很容易慢 500 倍。当 Scout 导入执行数千个这样的查询时,它会累加起来。

为什么偏移量速度慢

当你使用偏移量时,你是在告诉数据库要跳过前 N 行。即使没有返回跳过的这些行,数据库仍然会从磁盘读取它们并对它们进行排序。

数据库 可能 能够使用索引并避免获取整个行。我们的示例查询中使用主键索引,但仍然可以抓取。

使 ChunkById 更快的分块

事实证明,不使用偏移量就可以很容易地对结果进行分页。我们所要做的就是跟踪我们看到的最后一个 ID ,然后过滤结果,以便只获取我们未见到的行。如果结果是按 ID 升序排序的,我们可以使用一个简单的 WHERE ID > :last_id 子句进行筛选。查询语句最终就会是像这样:

select * from `users` where `id` > :last_id order by `id` asc limit 500;

使用这种技术后,加载最后一页和第一页加载速度是一样快。

Laravel 让这毫不费力。不要调用 chunk 而是调用 chunkById 方法(在 5.2 中添加)。查询构造器将会添加 where 语句、 order by 和 limit 。

API 与 chunk 完全相同。只要你不使用任何自定义的 order by 子句,它就是 4 个字符的变化。

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://mattallan.me/posts/making-larave...

译文地址:https://learnku.com/laravel/t/26935

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 2
lmaster

大赞,数据库是个需要我们好好学习研究的东西

4年前 评论

特地找了 267 万条数据来验证。

使用 chunk

[2019-10-11 10:50:27] local.INFO: select * from `20171220` order by `id` asc limit 10000 offset 0  
[2019-10-11 10:50:31] local.INFO: select * from `20171220` order by `id` asc limit 10000 offset 10000

  ....

[2019-10-11 11:16:14] local.INFO: select * from `20171220` order by `id` asc limit 10000 offset 2340000  
[2019-10-11 11:16:21] local.INFO: select * from `20171220` order by `id` asc limit 10000 offset 2350000

结果为:
file

使用ChunkById

[2019-10-11 11:24:09] local.INFO: select * from `20171220` where `id` > "0" order by `id` asc limit 10000
[2019-10-11 11:24:13] local.INFO: select * from `20171220` where `id` > "10000" order by `id` asc limit 10000

......

[2019-10-11 11:39:47] local.INFO: select * from `20171220` where `id` > "1990000" order by `id` asc limit 10000  
[2019-10-11 11:39:53] local.INFO: select * from `20171220` where `id` > "2000000" order by `id` asc limit 10000

结果为:
file

最后总结为:偏移量针对单个sql并不能提高sql的查询速度,但是对于百万以上数据整体看来还是提高查询速度很多的!

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!