mysql limit的分页用法与性能优化

mysql教程 limit 的性能问题

有个几千万条记录的表 on mysql 5.0.x,现在要读出其中几十万万条左右的记录

常用方法,依次循环:
select * from mytable where index_col = xxx limit offset, limit;

经验:如果没有blob/text字段,单行记录比较小,可以把 limit 设大点,会加快速度
问题:头几万条读取很快,但是速度呈线性下降,同时 mysql server cpu 99%
速度不可接受。

调用 explain select * from mytable where index_col = xxx limit offset, limit;
显示 type = all

在 mysql optimization 的文档写到"all"的解释
a full table scan is done for each combination of rows from the previous tables. this is normally not good if the table is the first table not marked const, and usually very bad in all other cases. normally, you can avoid all by adding indexes that allow row retrieval from the table based on constant values or column values from earlier tables.

看样子对于 all, mysql 就使用比较笨的方法,那就改用 range 方式?

因为 id 是递增的,也很好修改 sql

select * from mytable where id > offset and id < offset + limit and index_col = xxx

explain 显示 type = range, 结果速度非常理想,返回结果快了几十倍。

 

在 mysql 查询中使用了很多 limit 关键字,这就让我很感兴趣了,因为在我印象中, limit 关键字似乎更多被使用 mysql 数据库教程的程序员用来做查询分页(当然这也是一种很好的查询优化),那在这里举个例子,假设我们需要一个分页的查询 ,oracle中一般来说都是用以下 sql 句子实现:

select * from

( select a1.*, rownum rownum_

from testtable a1

where rownum > 20)

where rownum_ <= 1000

       这个语句就能查询到 testtable 表中的 20 到 1000 记录,而且还需要嵌套查询,效率不会太高,看看 mysql 的实现:

       select * from testtable a1 limit 20,980;

       这样就能返回 testtable 表中的 21 条到( 20 + 980 =) 1000 条的记录。

       实现语法确实简单,但如果要说这里两个 sql 语句的效率,那就很难做比较了,因为在 mysql 中 limit 选项有多种不同的解释方式,不同方式下的速度差异是很大的,因此我们不能从这语句的简洁程度就说谁的效率高。

       不过对程序员来说,够简单就好,因为维护成本低,呵呵。

       下面讲讲这个 limit 的语法吧:

       select ……. --select 语句的其他参数

[limit {[offset,] row_count | row_count offset offset}]

这里 offset 是偏移量(这个偏移量的起始地址是 0 ,而不是 1 ,这点很容易搞错的)顾名思义就是离开起始点的位置,而 row-count 也是很简单的,就是返回的记录的数量限制。

eg. select * from testtable a limit 10,20 where ….

这样就能使结果返回 10 行以后(包括 10 行自身)的符合 where 条件的 20 条记录。

那么如果没有约束条件就返回 10 到 29 行的记录。

       那这跟避免全表扫描有什么关系呢? 下面是 mysql 手册对 limit 参数优化扫描的一些说明:

在一些情况中,当你使用 limit 选项而不是使用 having 时, mysql 将以不同方式处理查询。

l          如果你用 limit 只选择其中一部分行,当 mysql 一般会做完整的表扫描时,但在某些情况下会使用索引(跟 ipart 有关)。

l          如果你将 limit n 与 order by 同时使用,在 mysql 找到了第一个符合条件的记录后,将结束排序而不是排序整个表。

l          当 limit n 和 distinct 同时使用时, mysql 在找到一个记录后将停止查询。

l          某些情况下, group by 能通过顺序读取键 ( 或在键上做排序 ) 来解决,并然后计算摘要直到键值改变。在这种情况下, limit n 将不计算任何不必要的 group 。

l          当 mysql 完成发送第 n 行到客户端,它将放弃余下的查询。

l          而 limit 0 选项总是快速返回一个空记录。这对检查查询并且得到结果列的列类型是有用的。

l          临时表的大小使用 limit # 计算需要多少空间来解决查询。

 

百万数据模糊查找大改进!!!!!! (0.03 sec)

 

select id,name from user where name like '%83%' or key like '%83%' limit 0,25;

分页

mysql中limit的用法详解[数据分页常用]

在我们使用查询语句的时候,经常要返回前几条或者中间某几行数据,这个时候怎么办呢?不用担心,mysql已经为我们提供了这样一个功能。
select * from table   limit [offset,] rows | rows offset offset

limit 子句可以被用于强制 select 语句返回指定的记录数。limit 接受一个或两个数字参数。参数必须是一个整数常量。如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目。初 始记录行的偏移量是 0(而不是 1): 为了与 postgresql 兼容,mysql 也支持句法: limit # offset #。

mysql> select * from table limit 5,10;  // 检索记录行 6-15

//为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:
mysql> select * from table limit 95,-1; // 检索记录行 96-last.

//如果只给定一个参数,它表示返回最大的记录行数目:
mysql> select * from table limit 5;     //检索前 5 个记录行

//换句话说,limit n 等价于 limit 0,n。
1. select * from tablename <条件语句> limit 100,15

从100条记录后开始取15条 (实际取取的是第101-115条数据)

2. select * from tablename <条件语句> limit 100,-1

从第100条后开始-最后一条的记录

3. select * from tablename <条件语句> limit 15

相当于limit 0,15   .查询结果取前15条数据

时间: 2024-09-01 18:04:48

mysql limit的分页用法与性能优化的相关文章

MySQL内核月报 2014.11-MariaDB· 性能优化·filesort with small LIMIT optimization

从MySQL 5.6.2/MariaDB 10.0.0版本开始,MySQL/MariaDB针对"ORDER BY ...LIMIT n"语句实现了一种新的优化策略.当n足够小的时候,优化器会采用一个容积为n的优先队列来进行排序,而不是排序所有数据然后取出前n条. 这个新算法可以这么描述:(假设是ASC排序) 建立一个只有n个元素的优先队列(堆),根节点为堆中最大元素 根据其他条件,依次从表中取出一行数据 如果当前行的排序关键字小于堆头,则把当前元素替换堆头,重新Shift保持堆的特性

MySQL · 源码分析 · 词法分析及其性能优化

Table of Contents 1. 简介 2. 背景知识 3. 查找树的实现 3.1. 树的查找 3.2. 树的产生 4. 试试折半查找 5. 总结 简介 MySQL 支持标准的 SQL 语言,具体实现的时候必然要涉及到词法分析和语法分析.早期的程序可能会优先考虑手工实现词法分析和语法分析,现在大多数场合下都会采用工具来简化实现.MySQL.PostgreSQL 等采用 C/C++ 实现的开源数据库采用的是现代的 yacc/lex 组合,也就是 GNU bison/flex.其他比较流行的

MySQL内核月报 2014.12-MySQL· 性能优化·5.7 Innodb事务系统

背景知识 为了便于理解下文,我们先简单梳理下Innodb中的事务.视图.多版本的相关背景知识. 在Innodb中,每次开启一个事务时,都会为该session分配一个事务对象.而为了对全局所有的事务进行控制和协调,有一个全局对象trx_sys,对trx_sys相关成员的操作需要trx_sys->mutex锁. Innodb使用一种称做ReadView(视图)的对象来判断事务的可见性(也就是ACID中的隔离性).根据可见性原则,某个新开启的事务不应该看到其他未提交的事务. Innodb在执行一个SE

深入剖析-关于分页语句的性能优化

分页语句是数据库开发和应用场景比较常见的需求,即按照特定的where条件进行过滤,然后在按照一个或者多个条件进行排序(如果不进行排序无法确执行时候无法返回相同的结果),最后取其中的前十行或者几十行. 一般分页语句消耗资源的地方有两点: 1.返回where条件过滤的结果集: 2.是对这个结果集进行排序,如果表过大同时对返回的结果集排序势必导致性能严重下降,针对分页语句性能低下的原因. 优化分页语句的核心思想: 1.创建效率高的索引返回尽量少的结果集排序: 2.因为索引是有序的,直接让数据库读取有序

MySQL内核月报 2014.12-MySQL· 性能优化·thread pool 原理分析

大连接问题 现有mysql 处理客户端连接的方式会触发mysql 新建一个线程来处理新的连接,新建的线程会处理该连接所发送的所有 SQL 请求,即 one-thread-per-connection 的方式,其创建连接的堆栈为: 线程建立后,处理请求的堆栈如下: 0 mysql_execute_command 1 0x0000000000936f40 in mysql_parse 2 0x0000000000920664 in dispatch_command 3 0x000000000091e

MySQL内核月报 2014.12-MySQL· 性能优化·并行复制外建约束问题

背景: mysql 主备同步是通过binlog来进行的,备库的 IO 线程从主库拉取binlog,SQL线程将拉取的binlog应用到备库,在5.6之前,备库只有一个线程应用binlog,主库的更新量大,且备库的执行效率低时,就会造成了大量从主库拉取的binlog来不及执行,因此造成了主备延迟问题.为了解决主备延迟,需要提高备库的执行效率,阿里MySQL 设计并开发了并行复制功能,所谓并行复制,指的是应用binlog的线程数量是多个的,而不是原生的单个线程,经过测试可以极大的提高复制性能(有3X

MySQL内核月报 2014.12-MySQL· 性能优化·Bulk Load for CREATE INDEX

背景 MySQL5.6以后的版本提供了多种优化手段用于create index,比如online方式,Bulk Load方式. Online提供了非阻塞写入的方式创建索引,为运维提供了很大的便利. Bulk Load提升了索引创建的效率,减少了阻塞的时间. 这篇介绍下MySQL 5.7.5 Bulk Load的细节,并从查找,排序,redo,undo,page split等维度比较一下传统方式和Bulk Load方式. 传统方式 MySQL 5.7.5版本之前,create index使用的是和

mysql中大数据分页如何使用索引优化

使用覆盖索引 一个表建立在id,create_time上建立了索引. 如下2个sql语句,执行时间一样. 因为查询字段id被索引覆盖. select id from order_manage where create_time > '2014-01-01' order by create_time desc limit 100000,10 select a.id from order_manage a inner join ( select id from order_manage where

MySQL单表百万数据记录分页性能优化技巧_Mysql

测试环境: 先让我们熟悉下基本的sql语句,来查看下我们将要测试表的基本信息 use infomation_schema SELECT * FROM TABLES WHERE TABLE_SCHEMA = 'dbname' AND TABLE_NAME = 'product' 查询结果: 从上图中我们可以看到表的基本信息: 表行数:866633 平均每行的数据长度:5133字节 单表大小:4448700632字节 关于行和表大小的单位都是字节,我们经过计算可以知道 平均行长度:大约5k 单表总大