首页 > 数据库 >PostgreSQL - limit offset SQL优化

PostgreSQL - limit offset SQL优化

时间:2023-08-12 09:33:26浏览次数:52  
标签:PostgreSQL 分页 SQL xx limit OFFSET LIMIT 万行

这个案例来自项目组最近一直在做性能优化的一个案列,我们项目每周都有通过Kibana (EFLK) 导出性能周报,最近一周出现一个分页查询的API出现了slow call (响应大于1秒),我们对代码和SQL进行了review,Code部分这里省略掉,讲下SQL的部分,下面是SQL

select t.id, t.xx from xx_table t where xxx order by id limit 10000 offset 1000000;

OFFSET 和 LIMIT 有什么问题?

OFFSET 和 LIMIT 对于数据量少的项目来说是没有问题的。但是,当数据库里的数据量超过服务器内存能够存储的能力,并且需要对所有数据进行分页,问题就会出现。为了实现分页,每次收到分页请求时,数据库都需要进行低效的全表扫描。

什么是全表扫描?全表扫描 (又称顺序扫描) 就是在数据库中进行逐行扫描,顺序读取表中的每一行记录,然后检查各个列是否符合查询条件。这种扫描是已知最慢的,因为需要进行大量的磁盘 I/O,而且从磁盘到内存的传输开销也很大。

这意味着如果你有 5000万的数据,OFFSET 是100万,那么它需要获取所有这些记录 (包括那么多根本不需要的数据),将它们放入内存,然后获取 LIMIT 指定的 1万 条结果。也就是说为了获取一页的数据:2000万行中的100万行到101万行。
需要先获取 100 万行。这么做是多么低效?数据越多,情况就越糟。

下面是guithub上别人对 10 万行数据进行的 PoC

https://github.com/IvoPereira/Efficient-Pagination-SQL-PoC?ref=hackernoon.com

现在你应该知道这背后都发生了什么:OFFSET 越高,查询时间就越长。

下面是优化后的SQL

select t.id, t.xx from xx_table t where xxx and id>= xx limit 10000;

这是一种基于指针的分页。你要在本地保存上一次接收到的主键 (通常是一个 ID) 和 LIMIT,而不是 OFFSET 和 LIMIT,那么每一次的查询可能都与此类似。因为通过显式告知数据库最新行,数据库就确切地知道从哪里开始搜索(基于有效的索引),而不需要考虑目标范围之外的记录。如果我们的表没有主键,比如是具有多对多关系的表,那么就使用传统的 OFFSET/LIMIT 方式,只是这样做存在潜在的慢查询问题。所以在需要分页的表中使用自动递增的主键,即使只是为了分页。

 

在线SQL测试:https://www.db-fiddle.com

标签:PostgreSQL,分页,SQL,xx,limit,OFFSET,LIMIT,万行
From: https://www.cnblogs.com/hlkawa/p/17624297.html

相关文章

  • java之手搓简单ORM框架--SQL的UPDATA
    1.手搓简单SQL增删改查框架-更改1.1创建简单类,并使用泛型类,这里可能使用到之间写的三篇知识的内容,如果不了解的小伙伴可以去java高级之泛型java高级之映射java高级之反射当然,前提是必须要把数据库相关连接弄好,这里会专门出一篇java之jdbc现在咱们继续手搓框架开始叭!由于上......
  • MySQL 设置 IP 白名单
    1.登录MySQLmysql-uroot-p2.新增用户并授予权限MySQL8之前:grantallon*.*to'username'@'ip'identifiedby'password'withgrantoption;MySQL8开始:createuser'username'@'ip'identifiedwithmysql_native_pa......
  • MySQL数据库笔记(二)
    聚集函数聚集函数:SQL提供的方法统计函数count(字段):统计表中记录的个数.语法: selectcount(*)from表名; 练习: --统计exam中有多少个学生: selectcount(name)fromtb_exam; selectcount(id)fromtb_exam; selectcount(*)fromtb_exam;--根据任意字段进行统计......
  • SQL--函数
    SQL--函数函数是什么?函数是指一段可以直接被另一段程序调用的程序或代码。字符串函数selectconcat('hello','mysql');selectlower('Hello');selectupper('Hello');selectlpad('01',5,'-');selectrpad('01',5,'-');......
  • SQL去重,更新时间小的,保留最新时间的。
    UPDATEMANU_EXECUTIONSETIsDeleted=1,UpdateBy='ZJJ',IsOffline='1'WHEREIdin(SELECTME.IdFROMMANU_EXECUTIONMEJOIN(SELECTSFC,MIN(CreateOn)ASMaxCreateOnFROMMANU_EXECUTIONWHERECreateOn>'2023-07-01'......
  • 开源数据库Mysql_DBA运维实战 (DML/DQL语句)
    DML/DQLDMLINSERT  实现数据的 插入        实例:DELETE  实现数据的 删除        实例:UPDATE  实现数据的 更新         实例1:         实例2:     实例3:DQL DML/DQL编辑 DML语句数据库操纵语言: 插入数据INSERT、删......
  • 【源码解析】postgresql having clause 是如何实现的 (2)
    在上一篇中,主要探究了postgresql源码层面是怎么实现聚合函数的。本篇将探究havingclause是如何实现的。setupcreatetablefoo(aint,bint);insertintofooselectrandom()*i/2,random()*ifromgenerate_series(10,20)g(i);selecta,count(b)fromfoogrou......
  • java之手搓简单ORM框架--SQL的INSERT
    1.手搓简单SQL增删改查框架-插入1.1创建简单类,并使用泛型类,这里可能使用到之间写的三篇知识的内容,如果不了解的小伙伴可以去java高级之泛型java高级之映射java高级之反射当然,前提是必须要把数据库相关连接弄好,这里会专门出一篇java之jdbc现在直接手搓框架开始叭!1.2准备工......
  • MySQL运行错误:‘mysql‘不是内部或外部命令,也不是可运行程序,Windows添加环境变量
    1、Windows电脑安装MySQL5.7,打开cmd出现“'mysql'不是内部或外部命令,也不是可运行的程序或批处理文件。”2、出现以上情况基本断定为没有安装mysql或者是安装了mysql没有配置环境变量,下面进行配置环境变量找到mysql的安装目录,可以windows+r然后输入:services.msc3、找到my......
  • MySQL全文索引的分词机制介绍
    什么是全文查询的“分词机制”?分词机制,也常称为“分词”或“词条化”(Tokenization),是将一段连续的文本切分成若干独立的词汇或词条的过程。在很多文本处理和信息检索的任务中,分词是首要且关键的步骤。分词机制的重要性主要体现在以下几个方面:信息检索:搜索引擎......