热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

mysql快速分页-索引性能分析-索引-orderby-limit-offset-covering-index

*我们经常会碰到以下的场景mysql中的用户数据(以下例子中以邮件为例)达到上百万级别,单个用户的邮件上万,当进行用户邮件记录查询时需要支持按照时间,按照标题,和按照收件人进行排序,

* 我们经常会碰到以下的场景
  mysql中的用户数据(以下例子中以邮件为例)达到上百万级别,单个用户的邮件上万,
  当进行用户邮件记录查询时需要支持按照时间,按照标题,和按照收件人进行排序,
  排序之后还要分页显示(用户邮件可能会分上千页),当用户选择3000 页,5000页,
  或者是尾页的时候,性能很差


* 构造测试数据模型
  表结构
    create table user_mail
    (
          id int(9) NOT NULL auto_increment,
          user_id int(9) NOT NULL,
          subject varchar(128),
          creating_time datetime,
          from_addr varchar(128),
          detail varchar(1024),
          PRIMARY KEY(id)
    );
    数据库为MyISAM, 字符集Latin-1
    生成测试数据的程序,代码如下, 产生300万条数据, 对应1000个用户,数据300万条(每个人3000条左右浮动)

为了测试较差的情况,特别让其中一个用户关联大量记录, 执行下面的语句
    update user_mail set user_id=900 where user_id>900;
    数据统计,编号0 ~ 899的用户的邮件数目在3000左右浮动,900号用户的数据为30万( 下面的测试均针对900号用户进行查询 ),数据一共300万

  • 试验环境

使用本机mysql (5.0.21), 本机配置, IBM think pad T61, 双核1.8G, 2G内存

  •     查询要求,分页查询某人的邮件,按照subject进行排序
  • 普通做法

    创建索引
    create index i_user_mail_subject on user_mail(user_id,subject);
   
    下面是执行的查询
    select * from user_mail where user_id=900 order by subject limit 100 offset ???
   
    offset 执行时间
    100        0.01秒
    1000    0.03秒
    10000    0.25秒
    100000    1.63秒
   
    最差情况的这个用户,当我选择尾页邮件的时候,数据库的负载极高,而且耗时超过2秒

  • 优化做法   

    创建索引
    create index i_user_mail_subject1 on user_mail(user_id,subject,id);
   
    下面是执行的查询
    select * from user_mail um
    inner join (
        select id from user_mail where user_id=900 order by subject limit 100 offset ???
    ) page on page.id=um.id;

    offset 执行时间
    100        0.01秒
    1000    0.02秒
    10000    0.03秒
    100000    0.24秒
   
    优化做法的sql语句和普通做法的sql是等价的,但是速度相差8倍左右
    可以看到当查询offset 10000时,只用了30ms,性能杠杠的

  • 优化原理

    covering index
    查询的所有字段在索引里都可以找到,这样查询的时候只用找索引就可以了
    这就是为什么优化算法中建立索引是三列主键
    select id from user_mail where user_id=900 order by subject limit 100 offset 10000
    上面的sql会很快,因为id, user_id, subject都能应用索引
    如果写成
    select * from user_mail where user_id=900 order by subject limit 100 offset 10000
    就会慢很多
   
    所以优化算法中先查询出小结果集(100条)的id, 然后再进行join查询,查询其他字段的值


推荐阅读
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • 本文由编程笔记小编整理,介绍了PHP中的MySQL函数库及其常用函数,包括mysql_connect、mysql_error、mysql_select_db、mysql_query、mysql_affected_row、mysql_close等。希望对读者有一定的参考价值。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 高质量SQL书写的30条建议
    本文提供了30条关于优化SQL的建议,包括避免使用select *,使用具体字段,以及使用limit 1等。这些建议是基于实际开发经验总结出来的,旨在帮助读者优化SQL查询。 ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • Java学习笔记之使用反射+泛型构建通用DAO
    本文介绍了使用反射和泛型构建通用DAO的方法,通过减少代码冗余度来提高开发效率。通过示例说明了如何使用反射和泛型来实现对不同表的相同操作,从而避免重复编写相似的代码。该方法可以在Java学习中起到较大的帮助作用。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
author-avatar
xzcxzfvxvc
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有