Mysql千万级别数据优化方案总结
MySQL百万到千万级别数据量的优化方案

MySQL百万到千万级别数据量的优化⽅案百万级字段选择优化表字段 not null,因为 null 值很难查询优化且占⽤额外的索引空间,推荐默认数字 0。
数据状态类型的字段,⽐如 status, type 等等,尽量不要定义负数,如 -1。
因为这样可以加上 UNSIGNED,数值容量就会扩⼤⼀倍。
可以的话⽤ TINYINT、SMALLINT 等代替 INT,尽量不使⽤ BIGINT,因为占的空间更⼩。
字符串类型的字段会⽐数字类型占的空间更⼤,所以尽量⽤整型代替字符串,很多场景是可以通过编码逻辑来实现⽤整型代替的。
字符串类型长度不要随意设置,保证满⾜业务的前提下尽量⼩。
⽤整型来存 IP。
单表不要有太多字段,建议在20以内。
为能预见的字段提前预留,因为数据量越⼤,修改数据结构越耗时。
索引设计优化索引,空间换时间的优化策略,基本上根据业务需求设计好索引,⾜以应付百万级的数据量,养成使⽤ explain 的习惯,关于 explain 也可以访问:explain 让你的 sql 写的更踏实了解更多。
⼀个常识:索引并不是越多越好,索引是会降低数据写⼊性能的。
索引字段长度尽量短,这样能够节省⼤量索引空间;取消外键,可交由程序来约束,性能更好。
复合索引的匹配最左列规则,索引的顺序和查询条件保持⼀致,尽量去除没必要的单列索引。
值分布较少的字段(不重复的较少)不适合建索引,⽐如像性别这种只有两三个值的情况字段建⽴索引意义不⼤。
需要排序的字段建议加上索引,因为索引是会排序的,能提⾼查询性能。
字符串字段使⽤前缀索引,不使⽤全字段索引,可⼤幅减⼩索引空间。
查询语句优化尽量使⽤短查询替代复杂的内联查询。
查询不使⽤ select *,尽量查询带索引的字段,避免回表。
尽量使⽤ limit 对查询数量进⾏限制。
查询字段尽量落在索引上,尤其是复合索引,更需要注意最左前缀匹配。
拆分⼤的 delete / insert 操作,⼀⽅⾯会锁表,影响其他业务操作,还有⼀⽅⾯是 MySQL 对 sql 长度也是有限制的。
MySQL千万级数据分区存储及查询优化

MySQL千万级数据分区存储及查询优化作为传统的关系型数据库,MySQL因其体积⼩、速度快、总体拥有成本低受到中⼩企业的热捧,但是对于⼤数据量(百万级以上)的操作显得有些⼒不从⼼,这⾥我结合之前开发的⼀个web系统来介绍⼀下MySQL数据库在千万级数据量的情况下如何优化提升查询速度。
⼀、基本业务需求该系统包括硬件系统和软件系统,由中科院计算所开发的⽆线传感器⽹络负责实时数据的监测和回传到MySQL数据库,我们开发的软件系统负责对数据进⾏实时计算,可视化展⽰及异常事件报警监测。
宫殿的温湿度等数据都存储在data表中,由于业务需要,data表中旧的数据要求不能删除,经过初步估算,⼀年的数据量⼤概为1200万条,之前的系统当数据量到达百万级时查询响应速度很慢,导致数据加载延迟很⼤,所以很有必要进⾏数据库的优化查询,提升响应速度。
结合故宫温湿度监测系统EasiWeb 7.1的data表查询,这⾥主要从以下三个⽅⾯详解MySQL的分区优化技术:(1)EasiWeb 7.1系统data表基于分表、分区和索引的优化⽅案对⽐。
(2)EasiWeb 7.1系统中采⽤的优化⽅案及实施步骤(3)系统模拟产⽣1500万数据的优化前后对⽐测试⼆、data表优化⽅案选择针对故宫系统⼤数据量时提升响应速度及运⾏性能的问题,我们团队通过研究和论证,提出了三种⽅案:2.1 data表分表存储,联表查询原理解释分表即将⼀个表结构分解为多个⼦表,这些⼦表可以同⼀个数据库下,也可以在不同的数据库下,查询的时候通过代码控制,⽣成多条查询语句,进⾏多项⼦表联查,最后汇总结果,整体上的查询结果与单表⼀样,但平均相应速度更快。
实现⽅式采⽤merge分表,划分的标准可以选取时间(collectTime)作为参数。
主表类似于⼀个壳⼦,逻辑上封装了⼦表,实际上数据都是存储在⼦表中。
我们在每年的1⽉1⽇创建⼀个⼦表data_20XX,然后将这些⼦表union起来构成⼀个主表。
MySQL千万级别大表,你要如何优化?

当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化:
单表优化
除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑、部署、运维的各种复杂度,一 般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的。而事实上很多时候MySQL 单表的性能依然有不少优化空间,甚至能正常支撑千万级以上的数据量:
引擎
目前广泛使用的是MyISAM和InnoDB两种引擎:
MyISAM
MyISAM引擎是MySQL 5.1及之前版本的默认引擎,它的特点是:
不支持行锁,读取时对需要读到的所有表加锁,写入时则对表加排它锁 不支持事务 不支持外键 不支持崩溃后的安全恢复 在表有读取查询的同时,支持往表中插入新纪录 支持BLOB和TEXT的前500个字符索引,支持全文索引 支持延迟更新索引,极大提升写入性能 对于不会进行修改的表,支持压缩表,极大减少磁盘空间占用
innodb_log_buffer_size:InnoDB存储引擎的事务日志所使用的缓冲区,一般来说不建议超过32MB
query_cache_size:缓存MySQL中的ResultSet,也就是一条SQL语句执行的结果集,所以仅仅只能针对select语 句。当某个表的数据有任何任何变化,都会导致所有引用了该表的select语句在Query Cache中的缓存数据失 效。所以,当我们的数据变化非常频繁的情况下,使用Query Cache可能会得不偿失。根据命中率 (Qcache_hits/(Qcache_hits+Qcache_inserts)*100))进行调整,一般不建议太大,256MB可能已经差不多了,大 型的配置型静态数据可适当调大. 可以通过命令show status like 'Qcache_%'查看目前系统Query catch使用大小
(转)优化GroupBy--MYSQL一次千万级连表查询优化

(转)优化GroupBy--MYSQL⼀次千万级连表查询优化概述:交代⼀下背景,这算是⼀次项⽬经验吧,属于公司⼀个已上线平台的功能,这算是离职⼈员挖下的坑,随着数据越来越多,原本的SQL查询变得越来越慢,⽤户体验特别差,因此SQL优化任务交到了我⼿上。
这个SQL查询关联两个数据表,⼀个是攻击IP⽤户表主要是记录IP的信息,如第⼀次攻击时间,地址,IP等等,⼀个是IP攻击次数表主要是记录每天IP攻击次数。
⽽需求是获取某天攻击IP信息和次数。
(以下SQL语句测试均在测试服务器上上,正式服务器的性能好,查询时间快不少。
)准备:查看表的⾏数:未优化前SQL语句为:SELECTattack_ip,country,province,city,line,info_update_time AS attack_time,sum( attack_count ) AS attack_timesFROM`blacklist_attack_ip`INNER JOIN `blacklist_ip_count_date` ON `blacklist_attack_ip`.`attack_ip` = `blacklist_ip_count_date`.`ip`WHERE`attack_count` > 0AND `date` BETWEEN '2017-10-13 00:00:00'AND '2017-10-13 23:59:59'GROUP BY`ip`LIMIT 10 OFFSET 1000123456789101112131415161718先EXPLAIN分析⼀下:这⾥看到索引是有的,但是IP攻击次数表blacklist_ip_count_data也⽤上了临时表。
那么这SQL不优化直接第⼀次执⾏需要多久(这⾥强调第⼀次是因为MYSQL带有缓存功能,执⾏过⼀次的同样SQL,第⼆次会快很多。
Mysql千万级别数据优化方案总结

Mysql千万级别数据优化方案目录目录 (1)一、目的与意义 (1)1) 说明 (1)二、解决思路与根据(本测试表中数据在千万级别) (2)1) 建立索引 (2)2) 数据体现(主键非索引,实际测试结果其中fid建立索引) (2)3) MySQL分页原理 (2)4) 经过实际测试当对表所有列查询时 (3)三、总结 (3)1) 获得分页数据 (3)2) 获得总页数:创建表记录大数据表中总数通过触发器来维护 (3)一、目的与意义1)说明在MySql单表中数据达到千万级别时数据的分页查询结果时间过长,对此进行优达到最优效果,也就是时间最短;(此统计利用的jdbc连接,其中fid为该表的主键;)二、解决思路与根据(本测试表中数据在千万级别)1)建立索引优点:当表中有大量记录时,若要对表进行查询,第一种搜索信息方式是全表搜索,是将所有记录一一取出,和查询条件进行一一对比,然后返回满足条件的记录,这样做会消耗大量数据库系统时间,并造成大量磁盘I/O操作;第二种就是在表中建立索引,然后在索引中找到符合查询条件的索引值,最后通过保存在索引中的ROWID(相当于页码)快速找到表中对应的记录。
缺点:当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降低了数据的维护速度。
2)数据体现(主键非索引,实际测试结果其中fid建立索引)未创建索引:SELECT fid from t_history_data LIMIT 8000000,10 结果:13.396s创建索引:SELECT fid from t_history_data LIMIT 8000000,10 结果:2.896sselect * from t_history_data where fid in ( 任意十条数据的id ) 结果:0.141s首先通过分页得到分页的数据的ID,将ID拼接成字符串利用SQL语句select * from table where ID in (ID字符串)此语句受数据量大小的影响比较小(如上测试);3)MySQL分页原理MySQL的limit工作原理就是先读取n条记录,然后抛弃前n条,读m条想要的,所以n越大,性能会越差。
MySQL对于千万级的大表要怎么优化?

MySQL对于千万级的⼤表要怎么优化?千万级,MySQL实际上确实不是什么压⼒,InnoDB的存储引擎,使⽤的是B+树存储结构,千万级的数据量,基本也就是三到四层的搜索,如果有合适的索引,性能基本也不是问题。
但经常出现的情况是,业务上⾯的增长,导致数据量还会继续增长,为了应对这⽅⾯的问题⽽必须要做扩展了此时可能⾸先需要考虑的就是分表策略了。
当然分表,可能还有其它⼏个原因,⽐如表变⼤了,千万级的数据库,为了减少运维成本,降低风险,就想到了通过分表来解决问题,这都是⽐较合适的。
分表,还有另⼀个⽅⾯的意思,就是在数据量更⼤的情况下,为了分担业务压⼒,将数据表分到不同的实例中去,这样有两⽅⾯的好处:1. 降低业务风险,如果⼀套数据库集群出问题了,那⾄少还有其它的可以服务,这样被影响的业务可能只是⼀部分。
2. 降低运维成本,如果数据库想要做迁移,或者正常维护等操作了,那涉及到的数据量⼩,下线时间短,操作快,从⽽对业务影响也就⼩了。
这种⽅式,我们称之为“分实例”。
分表的话,还是要根据具体的业务逻辑等⽅⾯来做,这⽅⾯有更精彩的回答,我这⾥贴⼀下:========================================分库分表是MySQL永远的话题,⼀般情况下认为MySQL是个简单的数据库,在数据量⼤到⼀定程度之后处理查询的效率降低,如果需要继续保持⾼性能运转的话,必须分库或者分表了。
关于数据量达到多少⼤是个极限这个事⼉,本⽂先不讨论,研究源码的同学已经证实MySQL或者Innodb内部的锁粒度太⼤的问题⼤⼤限制了MySQL提供QPS的能⼒或者处理⼤规模数据的能⼒。
在这点上,⼀般的使⽤者只好坐等官⽅不断推出的优化版本了。
在⼀般运维的⾓度来看,我们什么情况下需要考虑分库分表?⾸先说明,这⾥所说的分库分表是指把数据库数据的物理拆分到多个实例或者多台机器上去,⽽不是类似分区表的原地切分。
原则零:能不分就不分。
Mysql大数据量查询优化思路详析

Mysql⼤数据量查询优化思路详析⽬录1. 千万级别⽇志查询的优化2. ⼏百万⿊名单库的查询优化3. Mybatis批量插⼊处理问题项⽬场景:Mysql⼤表查询优化,理论上千万级别以下的数据量Mysql单表查询性能处理都是可以的。
问题描述:在我们线上环境中,出现了mysql⼏千万级别的⽇志查询、⼏百万级别的⿊名单库查询分页查询及条件查询都慢的问题,针对Mysql表优化做了⼀些优化处理。
原因分析:⾸先说⼀下⽇志查询,在Mysql中如果索引加的⽐较合适,⾛索引情况下千万级别查询不会超过⼀秒,Mysql查询的速度和检索的数据条数有关。
在Mybatis中,分页查询是先执⾏Count记录总数,再执⾏limit a,b 的⽅式来进⾏的,⽽Mysql的Count计数⽅式是将所有的数据过滤⼀遍进⾏累加,因此当⽇志表数据过千万时,统计⼀次就是⼗⼏秒钟的时间(这⾥是服务器环境,本地情况下甚⾄是⼏分钟)。
limit a,b的⽅式也⼀样,Mysql查询时会先⼀条⼀条数到第a条,然后向后再数b条作为查询结果,因此当起始⾏数越来越⼤时查询同样会变得很慢,也就是当你点第⼀页时可能⼀下就查出来了,当你点最后⼀页的时候可能⼏⼗秒才能查出来。
⿊名单库查询优化同理,也是需要通过条件优化。
在进⾏⼤批量数据落库时,使⽤的Mybatis批量插⼊,发现当批次数据超过3000时速度会急剧变慢,这是⼀个Mybatis娘胎⾥⾃带的问题,也需要进⾏解决。
解决⽅案:这⾥只简单说明优化的⼏个⽅向。
1. 千万级别⽇志查询的优化1. ⾸先说下⽇志查询,重点是优化⽆条件是分页查询,在⽆条件时,不使⽤MyBatis的分页插件,⽽是⾃⼰⼿写⼀个分页查询,由于MySql的count耗时过长,我们先优化他。
2. 优化Count:⽇志表的数据只增,不会出现中间某条删除,所以他的数据可以理解成是连续的,我们可以在内存中直接进⾏计数,记录count总数,或者给表添加⼀个⾃增的ID字段,直接select max(id)就是总数量,这样count查询的效率会提升到毫秒级别。
记一次mysql千万订单汇总查询优化

记⼀次mysql千万订单汇总查询优化正⽂公司订单系统每⽇订单量庞⼤,有很多表数据超千万。
公司SQL优化这块做的很不好,可以说是没有做,所以导致查询很慢。
节选某个功能中的⼀句SQL EXPLAIN查看执⾏计划,EXPLAIN + SQL 查看SQL执⾏计划⼀个索引没⽤到,受影响⾏接近2000万,难怪会慢。
原来的SQL打印出来估计有好⼏张A4纸,我发个整理后的简版。
SELECT COUNT(t.w_order_id) lineCount, SUM(ROUND(t.feel_total_money / 100, 2)) AS lineTotalFee, SUM(ROUND(t.feel_fact_money / 100, 2)) AS lineFactFeeFROM w_orders_his tWHERE 1=1 AND DATE_FORMAT(t.create_time, '%Y-%m-%d') >= STR_TO_DATE(#{beginTime},'%Y-%m-%d') AND DATE_FORMAT(t.create_time, '%Y-%m-%d') <= STR_TO_DATE(#{endTime},'%Y-%m-%d') AND t.pay_state = #{payState} AND t.store_id LIKE '%#{storeId}%' limit 0,10这条sql需求是在两千万的表中捞出指定时间和条件的订单进⾏总数总⾦额汇总处理。
优化sql需要根据公司的业务,技术的架构等,且针对不同业务每条SQL的优化都是有差异的。
优化点1:AND DATE_FORMAT(t.create_time, '%Y-%m-%d') >= STR_TO_DATE(#{beginTime},'%Y-%m-%d')AND DATE_FORMAT(t.create_time, '%Y-%m-%d') <= STR_TO_DATE(#{endTime},'%Y-%m-%d')我们知道sql中绝对要减少函数的使⽤,像左边DATE_FORMAT(t.create_time, '%Y-%m-%d') 是绝对禁⽌使⽤的,如果数据库有⼀百万数据那么就会执⾏⼀百万次函数,⾮常⾮常影响效率。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Mysql千万级别数据优化方案
目录
目录 (1)
一、目的与意义 (2)
1)说明 (2)
二、解决思路与根据(本测试表中数据在千万级别) (2)
1)建立索引 (2)
2)数据体现(主键非索引,实际测试结果其中fid建立索引) (2)
3)MySQL分页原理 (2)
4)经过实际测试当对表所有列查询时 (2)
三、总结 (3)
1)获得分页数据 (3)
2)获得总页数:创建表记录大数据表中总数通过触发器来维护 (3)
一、目的与意义
1)说明
在MySql单表中数据达到千万级别时数据的分页查询结果时间过长,对此进行优达
到最优效果,也就是时间最短;(此统计利用的jdbc连接,其中fid为该表的主键;)
二、解决思路与根据(本测试表中数据在千万级别)
1)建立索引
优点:当表中有大量记录时,若要对表进行查询,第一种搜索信息方式是全表搜
索,是将所有记录一一取出,和查询条件进行一一对比,然后返回满足条件的记
录,这样做会消耗大量数据库系统时间,并造成大量磁盘I/O操作;第二种就是
在表中建立索引,然后在索引中找到符合查询条件的索引值,最后通过保存在索
引中的ROWID(相当于页码)快速找到表中对应的记录。
缺点:当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,降
低了数据的维护速度。
2)数据体现(主键非索引,实际测试结果其中fid建立索引)
未创建索引:SELECT fid from t_history_data LIMIT 8000000,10结果:13.396s
创建索引:SELECT fid from t_history_data LIMIT 8000000,10结果:2.896s
select*fromt_history_datawherefidin (任意十条数据的id )结果:0.141s
首先通过分页得到分页的数据的ID,将ID拼接成字符串利用SQL语句
select * from table where ID in (ID字符串)此语句受数据量大小的影响比较小
(如上测试);
3)MySQL分页原理
MySQL的limit工作原理就是先读取n条记录,然后抛弃前n条,读m条想要
的,所以n越大,性能会越差。
优化前SQL: SELECT * FROM v_history_data LIMIT 5000000, 1010.961s
优化后SQL: SELECT * FROM v_history_data INNER JOIN (SELECT fid
FROM t_history_data LIMIT 5000000, 10) a USING (fid)1.943s
分别在于,优化前的SQL需要更多I/O浪费,因为先读索引,再读数据,然后
抛弃无需的行。
而优化后的SQL(子查询那条)只读索引(Cover index)就可以了,
然后通过member_id读取需要的列
4)经过实际测试当对表所有列查询时
select * from table 会比select (所有列名)from table 快些(以查询8000000
处数据分页实验)。
select * from t_history_data LIMIT 8000000,10结果:10.735s
select(总共14列)from t_history_data LIMIT 8000000,10结果:11.594s
三、总结
1)获得分页数据
创建索引:CREATE UNIQUE INDEX index_name ON t_history_data (fid)
相应的查询语句:SELECT * FROM v_history_data INNER JOIN (SELECT fid
FROM t_history_dataLIMIT 5000000, 10) a USING (fid) (原理位于上方红色
标记处,该方法查询速度将近提升10倍)
相对应的有条件查询根据需要建立索引
2)获得总页数:创建表记录大数据表中总数通过触发器来维护
创建表:CREATE TABLE `t_total` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`tableName` char(25) DEFAULT NULL,
`sum` int(11) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
表初始化
写触发器
CREATE TRIGGER t1 AFTER INSERT
ON t_history_data FOR EACH ROW
BEGIN
DECLARE i int;
SELECT sum INTO i from t_total WHERE tablename = 't_history_data' ;
set i = i+1;
UPDATE t_total set sum=i where tablename = 't_history_data' ;
END
CREATE TRIGGER t2 AFTER DELETE
ON t_history_data FOR EACH ROW
BEGIN
DECLARE i int;
SELECT sum INTO i from t_total WHERE tablename = 't_history_data' ;
set i = i-1;
UPDATE t_total set sum=i where tablename = 't_history_data' ;
END。