原文地址:原创 mysql数据库千万级别数据的查询优化和分页测试作者:于堡舰 
本文为本人最近利用几个小时才分析总结出的原创文章,希望大家转载,但是要注明出处 
http://blog.sina.com.cn/s/blog_438308750100im0b.html 
有什么问题:yubaojian0616@163.com 于堡舰

我原来的公司是一家网络游戏公司,其中网站交易与游戏数据库结合通过ws实现的,但是交易记录存放在网站上,级别是千万级别的数据库是mysql数据库.

可能有人会问mysql是否支持千万级数据库,还有既然已经到了这个数据量公司肯定不差,为什么要用mysql而不用oracle这里我做一下解答 
  1. mysql绝对支持千万级数据库是可以肯定的, 
  2. 为什么选择择mysql呢? 
1> 第一也是最主要的一条是mysql他能做到。 
2> 在第一点前提下以下的就不是太重要了,mysql相对操作简单,测试容易,配置优化也相对容易很多 
3> 我们这里的数据仅仅是为了记录交易保证交易是被记录的,对于查询的还是相对少只有管理后台操作中需要对数据库进行查询 
4> 数据结构简单,而且每条记录都非常小,因为查询速度不管和记录条数有关和数据文件大小也有直接关系. 
5> 我们采用的是大小表的解决办法,每天大概需要插入数据库好几百万条,这里可能还是有人怀疑,其实没问题,如果批量插入我测试的在普通的pc机子上带该一个线程并发我插入的是6千万条记录大概需要“JDBC插入6000W条数据用时:9999297ms”,小表保存最近插入的内容,把几天前的保存到大表中,这里我说的就是大表大概6-7千万条数据;

带着这些疑问和求知欲望咱们来做一个测试,因为在那个时候我也不是dba不知道人家是怎么搞的能够做成这么大的数据量,我们平时叶总探讨一些相关的内容 
  1.mysql的数据查询,大小字段要分开,这个还是有必要的,除非一点就是你查询的都是索引内容而不是表内容,比如只查询id等等 
  2.查询速度和索引有很大关系也就是索引的大小直接影响你的查询效果,但是查询条件一定要建立索引,这点上注意的是索引字段不能太多,太多索引文件就会很大那样搜索只能变慢, 
  3.查询指定的记录最好通过Id进行in查询来获得真实的数据.其实不是最好而是必须,也就是你应该先查询出复合的ID列表,通过in查询来获得数据 
  我们来做一个测试ipdatas表: 
  CREATE TABLE `ipdatas` ( 
   `id` INT(11) NOT NULL AUTO_INCREMENT, 
   `uid` INT(8) NOT NULL DEFAULT '0', 
   `ipaddress` VARCHAR(50) NOT NULL, 
   `source` VARCHAR(255) DEFAULT NULL, 
   `track` VARCHAR(255) DEFAULT NULL, 
   `entrance` VARCHAR(255) DEFAULT NULL, 
   `createdtime` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', 
   `createddate` DATE NOT NULL DEFAULT '0000-00-00', 
   PRIMARY KEY (`id`), 
   KEY `uid` (`uid`) 
  ) ENGINE=MYISAM AUTO_INCREMENT=67086110 DEFAULT CHARSET=utf8; 
  这是我们做的广告联盟的推广ip数据记录表,由于我也不是mysql的DBA所以这里咱们仅仅是测试 
  因为原来里面有大概7015291条数据 
  这里我们通过jdbc的batch插入6000万条数据到此表当中“JDBC插入6000W条数据用时:9999297ms”; 
  大概用了两个多小时,这里面我用的是batch大小大概在1w多每次提交,还有一点是每次提交的数据都很小,而且这里用的myisam数据表,因为我需要知道mysql数据库的大小以及索引数据的大小结果是 
  ipdatas.MYD 3.99 GB (4,288,979,008 字节) 
  ipdatas.MYI 1.28 GB (1,377,600,512 字节) 
  这里面我要说的是如果真的是大数据如果时间需要索引还是最好改成数字字段,索引的大小和查询速度都比时间字段可观。 
  步入正题: 
  1.全表搜索 
返回结构是67015297条数据 
   SELECT COUNT(id) FROM ipdatas; 
   SELECT COUNT(uid) FROM ipdatas; 
   SELECT COUNT(*) FROM ipdatas; 
   首先这两个全表数据查询速度很快,mysql中包含数据字典应该保留了数据库中的最大条数 
查询索引条件 
   SELECT COUNT(*) FROM ipdatas WHERE uid=1;   返回结果时间:2分31秒594 
   SELECT COUNT(id) FROM ipdatas WHERE uid=1;  返回结果时间:1分29秒609 
   SELECT COUNT(uid) FROM ipdatas WHERE uid=1; 返回结果时间:2分41秒813 
   第二次查询都比较快因为mysql中是有缓存区的所以增大缓存区的大小可以解决很多查询的优化,真可谓缓存无处不在啊在程序开发中也是层层都是缓存 
查询数据 
   第一条开始查询 
   SELECT * FROM ipdatas ORDER BY id DESC LIMIT 1,10 ; 31毫秒 
   SELECT * FROM ipdatas LIMIT 1,10 ; 15ms 
  
   第10000条开始查询 
   SELECT * FROM ipdatas ORDER BY id ASC LIMIT 10000,10 ; 266毫秒 
   SELECT * FROM ipdatas LIMIT 10000,10 ; 16毫秒 
   第500万条开始查询 
   SELECT * FROM ipdatas LIMIT 5000000,10 ;11.312秒 
   SELECT * FROM ipdatas ORDER BY id ASC LIMIT 5000000,10 ; 221.985秒 
   这两条返回结果完全一样,也就是mysql默认机制就是id正序然而时间却大相径庭 
   第5000万条开始查询 
   SELECT * FROM ipdatas LIMIT 60000000,10 ;66.563秒 (对比下面的测试) 
   SELECT * FROM ipdatas ORDER BY id ASC LIMIT 50000000,10; 1060.000秒 
   SELECT * FROM ipdatas ORDER BY id DESC LIMIT 17015307,10; 434.937秒 
   第三条和第二条结果一样只是排序的方式不同但是用时却相差不少,看来这点还是不如很多的商业数据库,像oracle和sqlserver等都是中间不成两边还是没问题,看来mysql是开始行越向后越慢,这里看来可以不排序的就不要排序了性能差距巨大,相差了20多倍 
查询数据返回ID列表 
   第一条开始查 
   select id from ipdatas order by id asc limit 1,10; 31ms 
   SELECT id FROM ipdatas LIMIT 1,10 ; 0ms 
  
   第10000条开始 
   SELECT id FROM ipdatas ORDER BY id ASC LIMIT 10000,10; 68ms 
   select id from ipdatas limit 10000,10;0ms 
   第500万条开始查询 
   SELECT id FROM ipdatas LIMIT 5000000,10; 1.750s 
   SELECT id FROM ipdatas ORDER BY id ASC LIMIT 5000000,10;14.328s 
   第6000万条记录开始查询 
   SELECT id FROM ipdatas LIMIT 60000000,10; 116.406s 
   SELECT id FROM ipdatas ORDER BY id ASC LIMIT 60000000,10; 136.391s 
   select id from ipdatas limit 10000002,10; 29.032s 
   select id from ipdatas limit 20000002,10; 24.594s 
   select id from ipdatas limit 30000002,10; 24.812s 
   select id from ipdatas limit 40000002,10; 28.750s  84.719s 
   select id from ipdatas limit 50000002,10; 30.797s  108.042s 
   select id from ipdatas limit 60000002,10; 133.012s  122.328s 
   select * from ipdatas limit 10000002,10; 27.328s 
   select * from ipdatas limit 20000002,10; 15.188s 
   select * from ipdatas limit 30000002,10; 45.218s 
   select * from ipdatas limit 40000002,10; 49.250s   50.531s 
   select * from ipdatas limit 50000002,10; 73.297s   56.781s 
   select * from ipdatas limit 60000002,10; 67.891s   75.141s 
   select id from ipdatas order by id asc limit 10000002,10; 29.438s 
   select id from ipdatas order by id asc limit 20000002,10; 24.719s 
   select id from ipdatas order by id asc limit 30000002,10; 25.969s 
   select id from ipdatas order by id asc limit 40000002,10; 29.860d 
   select id from ipdatas order by id asc limit 50000002,10; 32.844s 
   select id from ipdatas order by id asc limit 60000002,10; 34.047s 
   至于SELECT * ipdatas order by id asc 就不测试了 大概都在十几分钟左右 
   可见通过SELECT id 不带排序的情况下差距不太大,加了排序差距巨大 
   下面看看这条语句 
   SELECT * FROM ipdatas WHERE id IN (10000,100000,500000,1000000,5000000,10000000,2000000,30000000,40000000,50000000,60000000,67015297);
   耗时0.094ms 
   可见in在id上面的查询可以忽略不计毕竟是6000多万条记录,所以为什么很多lucene或solr搜索都返回id进行数据库重新获得数据就是因为这个,当然lucene/solr+mysql是一个不错的解决办法这个非常适合前端搜索技术,比如前端的分页搜索通过这个可以得到非常好的性能.还可以支持很好的分组搜索结果集,然后通过id获得数据记录的真实数据来显示效果真的不错,别说是千万级别就是上亿也没有问题,真是吐血推荐啊.

上面的内容还没有进行有条件的查询仅仅是一些关于orderby和limit的测试,请关注我的下一篇文件对于条件查询的1亿数据检索测试

mysql数据库千万级别数据的查询优化和分页测试的更多相关文章

  1. OpenLayers添加点【php请求MySQL数据库返回GeoJSON数据】

    php请求MySQL数据库返回GeoJSON数据的实现方法请参见: http://www.cnblogs.com/marost/p/6234514.html OpenLayers[v3.19.1-di ...

  2. EF 连接MySQL 数据库  保存中文数据后乱码问题

    EF 连接MySQL 数据库  保存中文数据后乱码问题 采用Code First 生成的数据库,MySQL数据库中,生成的表的编码格式为***** 发现这个问题后,全部手动改成UTF8(图是另一个表的 ...

  3. php 连接mysql数据库并显示数据 实例 转载

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...

  4. mysql数据库中插入数据INSERT INTO SET的优势

    往mysql数据库中插入数据.以前常用 INSERT INTO 表名 (列名1,列名2…) VALUES(列值1,列值2); 如果在PHP程序中,就会写成如下示例(往商品库里增加商品) $sql = ...

  5. 删除mysql数据库中表分区数据

    删除mysql数据库中表分区数据 zabbix 几个大表创建了分区,由于磁盘空间告警,特将3月前的分区给予删除. 1.查看表的数据占用磁盘空间情况 2.登录mysql中,查看表的分区情况. 3.删除表 ...

  6. 使用sqoop将MySQL数据库中的数据导入Hbase

    使用sqoop将MySQL数据库中的数据导入Hbase 前提:安装好 sqoop.hbase. 下载jbdc驱动:mysql-connector-java-5.1.10.jar 将 mysql-con ...

  7. 解决Python向MySQL数据库插入中文数据时出现乱码

    解决Python向MySQL数据库插入中文数据时出现乱码 先在MySQL命令行中输入如下语句查看结果: 只要character_set_client character_set_database ch ...

  8. MySQL数据库表的数据插入、修改、删除、查询操作及实例应用

    一.MySQL数据库表的数据插入.修改.删除和查询 CREATE DATABASE db0504; USE db0504; CREATE TABLE student ( sno ) NOT NULL ...

  9. python制作简单excel统计报表3之将mysql数据库中的数据导入excel模板并生成统计图

    python制作简单excel统计报表3之将mysql数据库中的数据导入excel模板并生成统计图 # coding=utf-8 from openpyxl import load_workbook ...

随机推荐

  1. Codeforces 599D Spongebob and Squares(数学)

    D. Spongebob and Squares Spongebob is already tired trying to reason his weird actions and calculati ...

  2. Web 前端最佳实践

    Web 最佳实践   前端   选择器 尽量使用ID选择器 基于Id的选择器:先使用ID选择器定位,然后再使用find方法精确查找   // Fast: $( "#container div ...

  3. codeforces 630H (组合数学)

    H - Benches Time Limit:500MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit S ...

  4. Python中的基本语句

    本文简单的介绍下Python的几个基本语句. print语句 print可同时打印多个表达式,只要将他们用逗号隔开. >>> name='Gumy' >>> gre ...

  5. Windows 8 之 windbg 配置

    怎么安装windbg? 在Win8中,要通过安装windows 8 SDK来安装. 安装之后,在C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x6 ...

  6. 常见MFC UI界面库

    Xtrme toolkit,BCGControlBar,SkinMagic,AppFace,Skin++,Uskin++,SYGUI,LibUIDK,GuiToolkit,GardenUI等等,除了后 ...

  7. 教你看懂邮件头信息<转载>

    MIME对于邮件系统的扩展是巨大的,因为在MIME出现以前,信件内容如果要包括声音和动画,就必须把它变为ASCII码或把二进制的信息变成可以传送的编码标准,而接收方必须经过解码才可以获得声音和图画信息 ...

  8. MySQL常用查询语句集合《转》

    一查询数值型数据: SELECT * FROM tb_name WHERE sum > 100; 查询谓词:>,=,<,<>,!=,!>,!<,=>,= ...

  9. C#操作Word (1)Word对象模型

    Word对象模型  (.Net Perspective) 本文主要针对在Visual Studio中使用C# 开发关于Word的应用程序 来源:Understandingthe Word Object ...

  10. Nginx 1.4.7图片缓存服务器

    软件包版本: Nginx 1.4.7 Ngx_cache_purge-2.0 Openssl-1.0.1 Pcre-8.32 二.安装编译: a)         下载pcre-8.32.tar.gz ...