使用递延join的Offset/Limit
递延连接(deferred join )是一种技术,它将对要求的列的访问推迟到应用了偏移量和限制之后 。
使用这种技术,我们创建一个内部查询 , 可以用特定的索引进行优化,以获得最大的速度,然后将结果连接到同一个表,以获取完整的行 。
它看起来像这样:
这种方法的好处可以根据你的数据集有很大的不同,但是这种方法允许数据库尽可能少地检查数据,以满足用户的意图 。
查询中 "昂贵的 "select *部分只在与内部查询相匹配的15条记录上运行 。所有数据的Select都被推迟了 , 因此被称为推迟join 。
这种方法不太可能比传统的偏移/限制性能差 , 尽管它是可能的,所以一定要在你的数据上进行测试!
Laravel实现
我们如何把这一点带到我们最喜欢的网络框架,如Laravel和Rails?
让我们具体看看Laravel,因为我不知道Rails 。
感谢Laravel的macroable特性,我们可以扩展Eloquent Query Builder来添加一个新的方法,叫做deferredPaginate 。为了保持一致性 , 我们将模仿常规分页的签名 。
我们将尝试做尽可能少的自定义工作,并将大部分工作留给 Laravel 。
这是我们要做的:
这应该为我们提供 LaravelLengthAwarePaginator 和延迟连接的所有好处!
一个Github仓库
递延Join和覆盖索引
还没有完成...
使用递延Join的主要好处是减少了数据库必须检索然后丢弃的数据量 。我们可以通过帮助数据库获得它需要的数据而更进一步 , 而无需获取底层行 。
这样做的方法称为“覆盖索引covering index”,它是确保快速偏移/限制分页的最终解决方案 。
覆盖索引是一个索引,在这个索引中,查询的所有需要的字段都包含在索引本身中 。当一个查询的所有部分都能被一个索引 "覆盖 "时,数据库根本不需要读取该行 , 它可以从索引中获得它需要的一切 。
请注意,覆盖索引并不是以任何特殊方式创建的 。它只是指一个索引满足了一个查询所需要的一切的情况 。一个查询上的覆盖索引很可能不是另一个查询上的覆盖索引 。
在接下来的几个例子中 , 我们将使用这个基本的表,我把它填满了~1000万条记录 。
让我们看一个仅select索引列的简单查询 。在这种情况下,我们将从email表中进行select contacts 。
在这种情况下,数据库根本不需要读取基础行 。在MySQL中 , 我们可以通过运行一个解释并查看额外的列来验证这一点:
extra: using index告诉我们,MySQL能够只使用索引来满足整个查询,而不看基础行 。
如果尝试select name from contacts limit 10 , 我们将期望MySQL必须到该行去获取数据,因为名字name没有被索引 。这正是发生的情况,由下面的解释显示 。
extra不再显示 using index , 所以我们没有使用覆盖索引 。
假设你每页有15条记录,你的用户想查看第1001页,你的内部查询最终会是这样的 。
select id from contacts order by id limit 15 OFFSET 150000
explain结果显示:
MySQL能够单看索引来执行这个查询 。它不会简单地跳过前15万行,在使用offset是没有办法的,但它不需要读取15万行 。(只有游标分页可以让你跳过所有的行) 。
即使使用覆盖索引和延迟连接,当你到达后面的页面时 , 结果也会变慢,尽管与传统的偏移/限制相比,它应该是最小的 。使用这些方法,你可以轻易地深入到数千页 。
更好的覆盖索引
这里的很多好处取决于拥有良好的覆盖索引,所以让我们稍微讨论一下 。一切都取决于您的数据和用户的使用模式 , 但是您可以采取一些措施来确保查询的最高命中率 。
推荐阅读
- linux服务器分区,linux服务器分区使用率突然增涨
- oracle中循环查询语句,oracle 循环查询结果集
- aneal00能升级鸿蒙吗,wkgan00能升级鸿蒙系统吗
- 微信公众号视频连接看不了,微信公众号视频看不了咋回事
- php数据库竖表 php数据表视图
- 如何查询sqlserver性能数据,sqlserver查询最新数据
- postgresql怎么创建数据库的简单介绍
- 鸿蒙2游戏评测下载软件,鸿蒙20玩机
- mysql最新版怎么中文 mysql怎么改成中文版