方法1: 直接使用数据库提供的SQL语句

  • 语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 LIMIT M,N
  • 适应场景: 适用于数据量较少的情况(元组百/千级)
  • 原因/缺点: 全表扫描,速度会很慢 且 有的数据库结果集返回不稳定(如某次返回1,2,3,另外的一次返回2,1,3). Limit限制的是从结果集的M位置处取出N条输出,其余抛弃.

方法2: 建立主键或唯一索引, 利用索引(假设每页10条)

  • 语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 WHERE id_pk > (pageNum*10) LIMIT M
  • 适应场景: 适用于数据量多的情况(元组数上万)
  • 原因: 索引扫描,速度会很快. 有朋友提出: 因为数据查询出来并不是按照pk_id排序的,所以会有漏掉数据的情况,只能方法3

方法3: 基于索引再排序

  • 语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 WHERE id_pk > (pageNum*10) ORDER BY id_pk ASC LIMIT M
  • 适应场景: 适用于数据量多的情况(元组数上万). 最好ORDER BY后的列对象是主键或唯一所以,使得ORDERBY操作能利用索引被消除但结果集是稳定的(稳定的含义,参见方法1)
  • 原因: 索引扫描,速度会很快. 但MySQL的排序操作,只有ASC没有DESC(DESC是假的,未来会做真正的DESC,期待...???)

方法4: 基于索引使用prepare

第一个问号表示pageNum,第二个?表示每页元组数

  • 语句样式: MySQL中,可用如下方法: PREPARE stmt_name FROM SELECT * FROM 表名称 WHERE id_pk > (?* ?) ORDER BY id_pk ASC LIMIT M
  • 适应场景: 大数据量
  • 原因: 索引扫描,速度会很快. prepare语句又比一般的查询语句快一点。

方法5: 利用MySQL支持ORDER操作可以利用索引快速定位部分元组,避免全表扫描

比如: 读第1000到1019行元组(pk是主键/唯一键).

SELECT * FROM your_table WHERE pk>=1000 ORDER BY pk ASC LIMIT 0,20

方法6: 利用"子查询/连接+索引"快速定位元组的位置,然后再读取元组.

比如(id是主键/唯一键,蓝色字体时变量)

利用子查询示例:

SELECT * FROM your_table WHERE id <=
(SELECT id FROM your_table ORDER BY id desc LIMIT ($page-1)*$pagesize ORDER BY id desc
LIMIT $pagesize

利用连接示例:

SELECT * FROM your_table AS t1
JOIN (SELECT id FROM your_table ORDER BY id desc LIMIT ($page-1)*$pagesize AS t2
WHERE t1.id <= t2.id ORDER BY t1.id desc LIMIT $pagesize;

mysql大数据量使用limit分页,随着页码的增大,查询效率越低下。

测试实验

1. 直接用limit start, count分页语句, 也是我程序中用的方法:

select * from product limit start, count

当起始页较小时,查询没有性能问题,我们分别看下从10, 100, 1000, 10000开始分页的执行时间(每页取20条)。

如下:

select * from product limit 10, 20   0.016秒
select * from product limit 100, 20   0.016秒
select * from product limit 1000, 20   0.047秒
select * from product limit 10000, 20   0.094秒

我们已经看出随着起始记录的增加,时间也随着增大, 这说明分页语句limit跟起始页码是有很大关系的,那么我们把起始记录改为40w看下(也就是记录的一般左右)

select * from product limit 400000, 20   3.229秒

再看我们取最后一页记录的时间

select * from product limit 866613, 20   37.44秒

像这种分页最大的页码页显然这种时间是无法忍受的。

从中我们也能总结出两件事情:

  1. limit语句的查询时间与起始记录的位置成正比
  2. mysql的limit语句是很方便,但是对记录很多的表并不适合直接使用。

2. 对limit分页问题的性能优化方法

利用表的覆盖索引来加速分页查询

我们都知道,利用了索引查询的语句中如果只包含了那个索引列(覆盖索引),那么这种情况会查询很快。

因为利用索引查找有优化算法,且数据就在查询索引上面,不用再去找相关的数据地址了,这样节省了很多时间。另外Mysql中也有相关的索引缓存,在并发高的时候利用缓存就效果更好了。

在我们的例子中,我们知道id字段是主键,自然就包含了默认的主键索引。现在让我们看看利用覆盖索引的查询效果如何。

这次我们之间查询最后一页的数据(利用覆盖索引,只包含id列),如下:

select id from product limit 866613, 20 0.2秒

相对于查询了所有列的37.44秒,提升了大概100多倍的速度

那么如果我们也要查询所有列,有两种方法,一种是id>=的形式,另一种就是利用join,看下实际情况:

SELECT * FROM product WHERE ID > =(select id from product limit 866613, 1) limit 20

查询时间为0.2秒!

另一种写法

SELECT * FROM product a JOIN (select id from product limit 866613, 20) b ON a.ID = b.id

查询时间也很短!

3. 复合索引优化方法

MySql 性能到底能有多高?MySql 这个数据库绝对是适合dba级的高手去玩的,一般做一点1万篇新闻的小型系统怎么写都可以,用xx框架可以实现快速开发。可是数据量到了10万,百万至千万,他的性能还能那么高吗?一点小小的失误,可能造成整个系统的改写,甚至更本系统无法正常运行!好了,不那么多废话了。

用事实说话,看例子:

数据表 collect ( id, title ,info ,vtype) 就这4个字段,其中 title 用定长,info 用text, id 是逐渐,vtype是tinyint,vtype是索引。这是一个基本的新闻系统的简单模型。现在往里面填充数据,填充10万篇新闻。最后collect 为 10万条记录,数据库表占用硬1.6G。

OK ,看下面这条sql语句:

select id,title from collect limit 1000,10;

很快;基本上0.01秒就OK,再看下面的

select id,title from collect limit 90000,10;

从9万条开始分页,结果?

8-9秒完成,my god 哪出问题了?其实要优化这条数据,网上找得到答案。看下面一条语句:

select id from collect order by id limit 90000,10;

很快,0.04秒就OK。 为什么?因为用了id主键做索引当然快。网上的改法是:

select id,title from collect where id>=(select id from collect order by id limit 90000,1) limit 10;

这就是用了id做索引的结果。可是问题复杂那么一点点,就完了。看下面的语句

select id from collect where vtype=1 order by id limit 90000,10; 很慢,用了8-9秒!

到了这里我相信很多人会和我一样,有崩溃感觉!vtype 做了索引了啊?怎么会慢呢?vtype做了索引是不错,你直接

select id from collect where vtype=1 limit 1000,10;

是很快的,基本上0.05秒,可是提高90倍,从9万开始,那就是0.05*90=4.5秒的速度了。和测试结果8-9秒到了一个数量级。

从这里开始有人提出了分表的思路,这个和dis #cuz 论坛是一样的思路。思路如下:

建一个索引表: t (id,title,vtype) 并设置成定长,然后做分页,分页出结果再到 collect 里面去找info 。 是否可行呢?实验下就知道了。

10万条记录到 t(id,title,vtype) 里,数据表大小20M左右。用

select id from t where vtype=1 order by id limit 90000,10;

很快了。基本上0.1-0.2秒可以跑完。为什么会这样呢?我猜想是因为collect 数据太多,所以分页要跑很长的路。limit 完全和数据表的大小有关的。其实这样做还是全表扫描,只是因为数据量小,只有10万才快。OK, 来个疯狂的实验,加到100万条,测试性能。加了10倍的数据,马上t表就到了200多M,而且是定长。还是刚才的查询语句,时间是0.1-0.2秒完成!分表性能没问题?

错!因为我们的limit还是9万,所以快。给个大的,90万开始

select id from t where vtype=1 order by id limit 900000,10;

看看结果,时间是1-2秒!why ?

分表了时间还是这么长,非常之郁闷!有人说定长会提高limit的性能,开始我也以为,因为一条记录的长度是固定的,mysql 应该可以算出90万的位置才对啊?可是我们高估了mysql 的智能,他不是商务数据库,事实证明定长和非定长对limit影响不大?怪不得有人说discuz到了100万条记录就会很慢,我相信这是真的,这个和数据库设计有关!

难道MySQL 无法突破100万的限制吗???到了100万的分页就真的到了极限?

答案是: NO 为什么突破不了100万是因为不会设计mysql造成的。下面介绍非分表法,来个疯狂的测试!一张表搞定100万记录,并且10G 数据库,如何快速分页!

好了,我们的测试又回到 collect表,开始测试结论是:

30万数据,用分表法可行,超过30万他的速度会慢道你无法忍受!当然如果用分表+我这种方法,那是绝对完美的。但是用了我这种方法后,不用分表也可以完美解决!

答案就是:复合索引! 有一次设计mysql索引的时候,无意中发现索引名字可以任取,可以选择几个字段进来,这有什么用呢?

开始的

select id from collect order by id limit 90000,10;

这么快就是因为走了索引,可是如果加了where 就不走索引了。抱着试试看的想法加了 search(vtype,id) 这样的索引。

然后测试

select id from collect where vtype=1 limit 90000,10;

非常快!0.04秒完成!

再测试:

select id ,title from collect where vtype=1 limit 90000,10;

非常遗憾,8-9秒,没走search索引!

再测试:search(id,vtype),还是select id 这个语句,也非常遗憾,0.5秒。

综上:如果对于有where 条件,又想走索引用limit的,必须设计一个索引,将where 放第一位,limit用到的主键放第2位,而且只能select 主键!

完美解决了分页问题了。可以快速返回id就有希望优化limit , 按这样的逻辑,百万级的limit 应该在0.0x秒就可以分完。看来mysql 语句的优化和索引时非常重要的!

———————————————————————————————————————————

https://blog.csdn.net/qq_35571554/article/details/82800463

这篇文章主要是就在公司实习的时候,对SQL优化工作作出的一些整理。

在公司实习的时候,导师分配了SQL慢查询优化的任务,任务是这样的:每周从平台中导出生产数据库的慢查询文件进行分析。进行SQL优化的手段也主要是修改SQL写法,或者新增索引。

现在从记录项目中的一点点做起。

(1)数据库中设置SQL慢查询
      一、第一步.开启mysql慢查询

方式一:

修改配置文件  在 my.ini 增加几行:  主要是慢查询的定义时间(超过2秒就是慢查询),以及慢查询log日志记录( slow_query_log)

方法二:通过MySQL数据库开启慢查询:

(2)分析慢查询日志         
       直接分析mysql慢查询日志 ,利用explain关键字可以模拟优化器执行SQL查询语句,来分析sql慢查询语句

例如:执行EXPLAIN SELECT * FROM res_user ORDER BYmodifiedtime LIMIT 0,1000

得到如下结果: 显示结果分析:

table |  type | possible_keys | key |key_len  | ref | rows | Extra  EXPLAIN列的解释:

table                 显示这一行的数据是关于哪张表的

type                  这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为const、eq_reg、ref、range、indexhe和ALL

rows                显示需要扫描行数

key                   使用的索引

(3)常见的慢查询优化

(1)索引没起作用的情况
    1. 使用LIKE关键字的查询语句

在使用LIKE关键字进行查询的查询语句中,如果匹配字符串的第一个字符为“%”,索引不会起作用。只有“%”不在第一个位置索引才会起作用。

2. 使用多列索引的查询语句

MySQL可以为多个字段创建索引。一个索引最多可以包括16个字段。对于多列索引,只有查询条件使用了这些字段中的第一个字段时,索引才会被使用。

(2)优化数据库结构
        合理的数据库结构不仅可以使数据库占用更小的磁盘空间,而且能够使查询速度更快。数据库结构的设计,需要考虑数据冗余、查询和更新的速度、字段的数据类型是否合理等多方面的内容。

1. 将字段很多的表分解成多个表

对于字段比较多的表,如果有些字段的使用频率很低,可以将这些字段分离出来形成新表。因为当一个表的数据量很大时,会由于使用频率低的字段的存在而变慢。

2. 增加中间表

对于需要经常联合查询的表,可以建立中间表以提高查询效率。通过建立中间表,把需要经常联合查询的数据插入到中间表中,然后将原来的联合查询改为对中间表的查询,以此来提高查询效率。

(3)分解关联查询
    将一个大的查询分解为多个小查询是很有必要的。

很多高性能的应用都会对关联查询进行分解,就是可以对每一个表进行一次单表查询,然后将查询结果在应用程序中进行关联,很多场景下这样会更高效,例如:

SELECT * FROM tag 
        JOIN tag_post ON tag_id = tag.id
        JOIN post ON tag_post.post_id = post.id
        WHERE tag.tag = 'mysql';
 
        分解为:
 
        SELECT * FROM tag WHERE tag = 'mysql';
        SELECT * FROM tag_post WHERE tag_id = 1234;
        SELECT * FROM post WHERE post.id in (123,456,567);
(4)优化LIMIT分页
      在系统中需要分页的操作通常会使用limit加上偏移量的方法实现,同时加上合适的order by 子句。如果有对应的索引,通常效率会不错,否则MySQL需要做大量的文件排序操作。

一个非常令人头疼问题就是当偏移量非常大的时候,例如可能是limit 10000,20这样的查询,这是mysql需要查询10020条然后只返回最后20条,前面的10000条记录都将被舍弃,这样的代价很高。

优化此类查询的一个最简单的方法是尽可能的使用索引覆盖扫描,而不是查询所有的列。然后根据需要做一次关联操作再返回所需的列。对于偏移量很大的时候这样做的效率会得到很大提升。

对于下面的查询:

select id,title from collect limit 90000,10;

该语句存在的最大问题在于limit M,N中偏移量M太大(我们暂不考虑筛选字段上要不要添加索引的影响),导致每次查询都要先从整个表中找到满足条件 的前M条记录,之后舍弃这M条记录并从第M+1条记录开始再依次找到N条满足条件的记录。如果表非常大,且筛选字段没有合适的索引,且M特别大那么这样的代价是非常高的。 试想,如我们下一次的查询能从前一次查询结束后标记的位置开始查找,找到满足条件的100条记录,并记下下一次查询应该开始的位置,以便于下一次查询能直接从该位置 开始,这样就不必每次查询都先从整个表中先找到满足条件的前M条记录,舍弃,在从M+1开始再找到100条满足条件的记录了。

方法一:虑筛选字段(title)上加索引
       title字段加索引  (此效率如何未加验证)

方法二:先查询出主键id值
select id,title from collect where id>=(select id from collect order by id limit 90000,1) limit 10;

原理:先查询出90000条数据对应的主键id的值,然后直接通过该id的值直接查询该id后面的数据。

方法三:“关延迟联”
如果这个表非常大,那么这个查询可以改写成如下的方式:

Select news.id, news.description from news inner join (select id from news order by title limit 50000,5) as myNew using(id);

这里的“关延迟联”将大大提升查询的效率,它让MySQL扫描尽可能少的页面,获取需要的记录后再根据关联列回原表查询需要的所有列。这个技术也可以用在优化关联查询中的limit。

方法四:建立复合索引 acct_id和create_time
    select * from acct_trans_log WHERE  acct_id = 3095  order by create_time desc limit 0,10

注意sql查询慢的原因都是:引起filesort

(5)分析具体的SQL语句
 1、两个表选哪个为驱动表,表面是可以以数据量的大小作为依据,但是实际经验最好交给mysql查询优化器自己去判断。
  例如:  select * from a where id in (select id from b );  
        对于这条sql语句它的执行计划其实并不是先查询出b表的所有id,然后再与a表的id进行比较。
mysql会把in子查询转换成exists相关子查询,所以它实际等同于这条sql语句:select * from a where exists(select * from b where b.id=a.id );

而exists相关子查询的执行原理是: 循环取出a表的每一条记录与b表进行比较,比较的条件是a.id=b.id . 看a表的每条记录的id是否在b表存在,如果存在就行返回a表的这条记录。

exists查询有什么弊端?
      由exists执行原理可知,a表(外表)使用不了索引,必须全表扫描,因为是拿a表的数据到b表查。而且必须得使用a表的数据到b表中查(外表到里表中),顺序是固定死的。

如何优化?
      建索引。但是由上面分析可知,要建索引只能在b表的id字段建,不能在a表的id上,mysql利用不上。

这样优化够了吗?还差一些。
      由于exists查询它的执行计划只能拿着a表的数据到b表查(外表到里表中),虽然可以在b表的id字段建索引来提高查询效率。
但是并不能反过来拿着b表的数据到a表查,exists子查询的查询顺序是固定死的。

为什么要反过来?
       因为首先可以肯定的是反过来的结果也是一样的。这样就又引出了一个更细致的疑问:在双方两个表的id字段上都建有索引时,到底是a表查b表的效率高,还是b表查a表的效率高?

该如何进一步优化?
       把查询修改成inner join连接查询:select * from a inner join b on a.id=b.id; (但是仅此还不够,接着往下看)

为什么不用left join 和 right join?
       这时候表之间的连接的顺序就被固定住了,比如左连接就是必须先查左表全表扫描,然后一条一条的到另外表去查询,右连接同理。仍然不是最好的选择。

为什么使用inner join就可以?
       inner join中的两张表,如: a inner join b,但实际执行的顺序是跟写法的顺序没有半毛钱关系的,最终执行也可能会是b连接a,顺序不是固定死的。如果on条件字段有索引的情况下,同样可以使用上索引。

那我们又怎么能知道a和b什么样的执行顺序效率更高?
       你不知道,我也不知道。谁知道?mysql自己知道。让mysql自己去判断(查询优化器)。具体表的连接顺序和使用索引情况,mysql查询优化器会对每种情况做出成本评估,最终选择最优的那个做为执行计划。

在inner join的连接中,mysql会自己评估使用a表查b表的效率高还是b表查a表高,如果两个表都建有索引的情况下,mysql同样会评估使用a表条件字段上的索引效率高还是b表的。

利用explain字段查看执行时运用到的key(索引)
       而我们要做的就是:把两个表的连接条件的两个字段都各自建立上索引,然后explain 一下,查看执行计划,看mysql到底利用了哪个索引,最后再把没有使用索引的表的字段索引给去掉就行了。

mysql慢查询优化相关推荐

  1. psql where里有自定义函数慢_阿里P8架构师谈:MySQL慢查询优化、索引优化、以及表等优化总结...

    MySQL优化概述 MySQL数据库常见的两个瓶颈是:CPU和I/O的瓶颈. CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候. 磁盘I/O瓶颈发生在装入数据远大于内存容量的时候,如果应 ...

  2. MySQL 慢查询优化

    为什么查询速度会慢 1.慢是指一个查询的响应时间长.一个查询的过程: 客户端发送一条查询给服务器 服务器端先检查查询缓存,如果命中了缓存,则立可返回存储在缓存中的结果.否则进入下一个阶段 服务器端进行 ...

  3. mysql数据库查询优化建议_mysql数据库查询优化的24条建议

    MySQL是一个强大的开源数据库.随着MySQL上的应用越来越多,MySQL逐渐遇到了瓶颈.这里提供一些关于Mysql 数据库查询优化的24条优化建议,仅供参考. Mysql 查询优化 1.使用慢查询 ...

  4. php mysql查询例子_php mysql一个查询优化的简单例子

    PHP+Mysql是一个最经常使用的黄金搭档,它们俩配合使用,能够发挥出最佳性能,当然,如果配合Apache使用,就更加Perfect了. 因此,需要做好对mysql的查询优化,下面通过一个简单的例子 ...

  5. 【MySQL】查询优化

    [MySQL]查询优化 1. 优化目的与目标 1.1 为什么要进行查询优化 1.1 MySQL优化目标 2. 优化流程及思路 2.1 调优时你需要关注哪些指标 2.1 合理监控 2.3 MySQL优化 ...

  6. MySQL 的查询优化

    说起 MySQL 的查询优化,相信大家收藏了一堆奇技淫巧:不能使用 SELECT *.不使用 NULL 字段.合理创建索引.为字段选择合适的数据类型-- 你是否真的理解这些优化技巧?是否理解其背后的工 ...

  7. 阿里P7架构师谈:MySQL慢查询优化、索引优化、以及表等优化总结

    MySQL优化概述 MySQL数据库常见的两个瓶颈是:CPU和I/O的瓶颈. CPU在饱和的时候一般发生在数据装入内存或从磁盘上读取数据时候. 磁盘I/O瓶颈发生在装入数据远大于内存容量的时候,如果应 ...

  8. mysql 子查询优化一例

    2019独角兽企业重金招聘Python工程师标准>>> 写在前面的话: 在慢查优化1和2里都反复强调过 explain 的重要性,但有时候肉眼看不出 explain 结果如何指导优化 ...

  9. mysql 测试快生产慢_生产上MySQL慢查询优化实战,SQL优化实战

    之前看了饿了么团队写的一篇博客:等等!这两个 Spring-RabbitMQ 的坑我们已经替你踩了.深受启发,一定要取个能吸引读者眼球的标题,当然除了响当当的标题以外,内容也要是干货.为什么会想取这样 ...

  10. 根据条件查询某条记录的条数_「性能与架构」MySQL 8 查询优化新工具 Explain Analyze...

    来源:性能与架构公众号 1. Explain Analyze 介绍 Explain 是我们常用的查询分析工具,可以对查询语句的执行方式进行评估,给出很多有用的线索. 但他仅仅是评估,不是实际的执行情况 ...

最新文章

  1. linux mailx 发邮件
  2. Linux文件查看命令图解
  3. Keepalived简介
  4. 分区表理论解析(上):SQL Server 2k52k8系列(一)
  5. 如何通过 Impex 在 SAP Commerce Cloud 创建一个新的 Component
  6. Mybatis多对多,复杂增删改查(特殊需求循环插入,分组查询)
  7. php增删改查参数化,JPA之使用JPQL语句进行增删改查
  8. Populating Additional data in Material master record
  9. C语言创建顺序表并插入元素 详细注释
  10. matlab 生命游戏
  11. 组态软件DIAView、扫码枪和第三方系统MES、SAP等应用
  12. pdf.js预览pdf文件流(base64)
  13. Azure虚拟机部署Skype for Business Server 三、部署Skype前端服务器
  14. 大数据-HDFS 文件副本和 Block 块存储
  15. 千万别轻易裸辞,今年工作太难找了!
  16. 自动提取网页文章或者文章的免费软件
  17. 十大常见的用户认知偏差
  18. 三个死刑犯的自白,哪个最牛?
  19. go语言怎么 控制一个变量输入的范围_四周入门Go语言(week01)
  20. 高中信息技术python及答案_高中信息技术《Python语言》模块试卷

热门文章

  1. (好文章搬个砖)MySQL索引背后的数据结构及算法原理
  2. []TLD code run
  3. 网络是怎样连接的-IP与以太网的包收发操作(三)
  4. C. Memory and De-Evolution 逆向思维
  5. 多线程等待/通知机制
  6. SQL数据库每日自动备份
  7. Eclipse中经常出现的问题解决方案
  8. 二 Djano模型层之模型字段选项
  9. PHP之mb_convert_case使用
  10. 模拟百度搜索框,输入时显示历史记录