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') 是绝对禁⽌使⽤的,如果数据库有⼀百万数据那么就会执⾏⼀百万次函数,⾮常⾮常影响效率。
mysql优化案例:千万级数据表partition实战应用案例
mysql优化案例:千万级数据表partition 实战应用案例目前系统的Stat 表以每天20W 条的数据量增加,尽管已经把超过3个月的数据dump 到其他地方,但表中仍然有接近2KW 条数据,容量接近2GB。
Stat 表已经加上索引,直接select where limit 的话,速度还是很快的,但一旦涉及到group by 分页,就会变得很慢。
据观察,7天内的group by 需要35~50s 左右。
运营反映体验极其不友好。
于是上网搜索MySQL 分区方案。
发现网上的基本上都是在系统性地讲解partition 的概念和种类,以及一些实验性质的效果,并不贴近实战。
通过参考MySQL手册以及自己的摸索,最终在当前系统中实现了分区,因为记录一下。
分区类型的选择Stat 表本身是一个统计报表,所以它的数据都是按日期来存放的,并且热数据一般只限于当天,以及7天内。
所以我选择了Range 类型来进行分区。
为当前表创建分区因为是对已有表进行改造,所以只能用alter 的方式:ALTER TABLE statPARTITION BY RANGE(TO_DAYS(dt)) (PARTITION p0 VALUES LESS THAN(0),PARTITION p190214 VALUES LESS THAN(TO_DAYS(#39;2019-02-14#39;)), PARTITION pm VALUES LESS THAN(MAXVALUE));这里有2点要注意:一是p0 分区,这是因为MySQL(我是5.7版) 有个bug,就是不管你查的数据在哪个区,它都会扫一下第一个区,我们每个区的数据都有几十万条,扫一下很是肉疼啊,所以为了避免不必要的扫描,直接弄个0数据分区就行了。
二是pm 分区,这个是最大分区。
假如不要pm,那你存2019-02-15的数据就会报错。
所以pm 实际上是给未来的数据一个预留的分区。
【优化】MySQL千万级大表优化解决方案
【优化】MySQL千万级⼤表优化解决⽅案问题概述使⽤阿⾥云rds for MySQL数据库(就是MySQL5.6版本),有个⽤户上⽹记录表6个⽉的数据量近2000万,保留最近⼀年的数据量达到4000万,查询速度极慢,⽇常卡死。
严重影响业务。
问题前提:⽼系统,当时设计系统的⼈⼤概是⼤学没毕业,表设计和sql语句写的不仅仅是垃圾,简直⽆法直视。
原开发⼈员都已离职,到我来维护,这就是传说中的维护不了就跑路,然后我就是掉坑的那个我尝试解决该问题,so,有个这个⽇志。
⽅案概述⽅案⼀:优化现有mysql数据库。
优点:不影响现有业务,源程序不需要修改代码,成本最低。
缺点:有优化瓶颈,数据量过亿就玩完了。
⽅案⼆:升级数据库类型,换⼀种100%兼容mysql的数据库。
优点:不影响现有业务,源程序不需要修改代码,你⼏乎不需要做任何操作就能提升数据库性能,缺点:多花钱⽅案三:⼀步到位,⼤数据解决⽅案,更换newsql/nosql数据库。
优点:没有数据容量瓶颈,缺点:需要修改源程序代码,影响业务,总成本最⾼。
以上三种⽅案,按顺序使⽤即可,数据量在亿级别⼀下的没必要换nosql,开发成本太⾼。
三种⽅案我都试了⼀遍,⽽且都形成了落地解决⽅案。
该过程⼼中慰问跑路的那⼏个开发者⼀万遍 :-)⽅案⼀详细说明:优化现有mysql数据库跟阿⾥云数据库⼤佬电话沟通 and Google解决⽅案 and 问群⾥⼤佬,总结如下(都是精华):1.数据库设计和表创建时就要考虑性能2.sql的编写需要注意优化4.分区4.分表5.分库1.数据库设计和表创建时就要考虑性能mysql数据库本⾝⾼度灵活,造成性能不⾜,严重依赖开发⼈员能⼒。
也就是说开发⼈员能⼒⾼,则mysql性能⾼。
这也是很多关系型数据库的通病,所以公司的dba通常⼯资巨⾼。
设计表时要注意:表字段避免null值出现,null值很难查询优化且占⽤额外的索引空间,推荐默认数字0代替null。
Mysql千万级大表优化策略
Mysql千万级⼤表优化策略1.优化sql以及索引1.1优化sql1、有索引但未被⽤到的情况(不建议)(1)避免like的参数以通配符开头时尽量避免Like的参数以通配符开头,否则数据库引擎会放弃使⽤索引⽽进⾏全表扫描。
以通配符开头的sql语句,例如:select * from t_credit_detail where Flistid like '%0'\G这是全表扫描,没有使⽤到索引,不建议使⽤。
不以通配符开头的sql语句,例如:select * from t_credit_detail where Flistid like '2%'\G很明显,这使⽤到了索引,是有范围的查找了,⽐以通配符开头的sql语句效率提⾼不少。
(2) 避免where条件不符合最左前缀原则。
最左前缀原则:mysql会⼀直向右匹配直到遇到范围查询(>、<、between、like)就停⽌匹配,⽐如a = 1 and b = 2 and c > 3 and d = 4 如果建⽴(a,b,c,d)顺序的索引,d是⽤不到索引的,如果建⽴(a,b,d,c)的索引则都可以⽤到,a,b,d的顺序可以任意调整(IN和=可以乱序)。
(3) 使⽤!= 或 <> 操作符时尽量避免使⽤!= 或 <>操作符,否则数据库引擎会放弃使⽤索引⽽进⾏全表扫描。
使⽤>或<会⽐较⾼效。
select * from t_credit_detail where Flistid != '2000000608201108010831508721'\G(4) 避免索引列参与计算应尽量避免在 where ⼦句中对字段进⾏表达式操作,这将导致引擎放弃使⽤索引⽽进⾏全表扫描。
select * from t_credit_detail where Flistid +1 > '2000000608201108010831508722'\G(5) 避免对字段进⾏null值判断应尽量避免在where⼦句中对字段进⾏null值判断,否则将导致引擎放弃使⽤索引⽽进⾏全表扫描,如:低效:select * from t_credit_detail where Flistid is null ;可以在Flistid上设置默认值0,确保表中Flistid列没有null值,然后这样查询:⾼效:select * from t_credit_detail where Flistid =0;(6) 避免使⽤or来连接条件应尽量避免在where⼦句中使⽤or来连接条件,否则将导致引擎放弃使⽤索引⽽进⾏全表扫描,如:低效:select * from t_credit_detail where Flistid ='2000000608201108010831508721' or Flistid = '10000200001';可以⽤下⾯这样的查询代替上⾯的 or 查询:⾼效:select from t_credit_detail where Flistid = '2000000608201108010831508721' union all select from t_credit_detail where Flistid = '10000200001';2、避免select *在解析的过程中,会将'*' 依次转换成所有的列名,这个⼯作是通过查询数据字典完成的,这意味着将耗费更多的时间。
mysql-优化-千万级数据SQL查询优化
提高mysql千万级大数据SQL查询优化30条经验(Mysql索引优化注意)1、对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2、应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:select id from t where num is null;可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:select id from t where num=0;3、应尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描。
4、应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:select id from t where num=10 or num=20;可以这样查询:select id from t where num=10union all select id from t where num=20;5、in 和 not in 也要慎用,否则会导致全表扫描,如:select id from t where num in(1,2,3);对于连续的数值,能用 between 就不要用 in:select id from t where num between 1 and 3;6、下面的查询也将导致全表扫描:select id from t where name like '李%'若要提高效率,可以考虑全文检索。
7、如果在 where 子句中使用参数,也会导致全表扫描。
因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。
然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。
如下面语句将进行全表扫描:select id from t where num=@num可以改为强制查询使用索引:select id from t with(index(索引名)) where num=@num8、应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。
MSSQL、MySQL数据库删除大批量千万级百万级数据的优化
MSSQL、MySQL数据库删除⼤批量千万级百万级数据的优化SQL Server上⾯删除1.6亿条记录,不能⽤Truncate(因为只是删除其中少部分数据)。
经过实验,每次删除400万条要花1.5 - 3⼩时,⽽且是越到后⾯越慢,正常的话,需要⼤约102个⼩时,⼤约4天半时间。
这在⽣产环境下是不能接受的。
经过⼀个处理之后,我每次删除400万条记录花5 - 6分钟,删除全部1.6亿条记录花了4 - 5个⼩时!为什么??每次删除记录,数据库都要相应地更新索引,这是很慢的IO操作,⽽且后⾯索引碎⽚越来越多,就更慢,这就是为什么⼀开始只花1.5⼩时,后⾯要3⼩时才能删除400万条记录的原因。
删除之前,做个完整备份。
我在删除前先保存当前索引的DDL,然后删除其索引,然后根据使⽤的删除条件建⽴⼀个临时的索引(这是提⾼速度的另外⼀个重要原因!)开始删除操作,完成之后再重建之前的索引。
如果需要保留的数据⽐较少的话,可以把要保留的数据备份出来。
在drop表。
重新创建,先不要急着创建索引、主键,把数据导回去,然后在建索引、约束之类的。
记得在删除的时候不要在记录⽇志的模式下⾯,否则⽇志⽂件就要爆了。
2、在My SQL数据库使⽤中,有的表存储数据量⽐较⼤,达到每天三百万条记录左右,此表中建⽴了三个索引,这些索引都是必须的,其他程序要使⽤。
由于要求此表中的数据只保留当天的数据,所以每当在凌晨的某⼀时刻当其他程序处理完其中的数据后要删除该表中昨天以及以前的数据,使⽤delete删除表中的上百万条记录时,MySQL删除速度⾮常缓慢每⼀万条记录需要⼤概4分钟左右,这样删除所有⽆⽤数据要达到⼋个⼩时以上,这是难以接受的。
查询MySQL官⽅⼿册得知删除数据的速度和创建的索引数量是成正⽐的,于是删除掉其中的两个索引后测试,发现此时删除速度相当快,⼀百万条记录在⼀分钟多⼀些,可是这两个索引其他模块在每天⼀次的数据整理中还要使⽤,于是想到了⼀个折中的办法:在删除数据之前删除这两个索引,此时需要三分钟多⼀些,然后删除其中⽆⽤数据,此过程需要不到两分钟,删除完成后重新创建索引,因为此时数据库中的数据相对较少,约三四⼗万条记录(此表中的数据每⼩时会增加约⼗万条),创建索引也⾮常快,约⼗分钟左右。
MySQL数据库优化的技术方法全汇总
MySQL数据库优化的技术方法全汇总MySQL数据库是一种开源的关系型数据库管理系统,广泛应用于各种Web应用和大型企业系统中。
然而,随着数据量的增加和业务规模的扩大,MySQL数据库的性能问题也逐渐凸显出来。
为了提高数据库的性能和稳定性,我们需要采取一系列的优化技术方法。
本文将全面汇总MySQL数据库优化的技术方法,包括索引优化、SQL语句优化、配置优化、硬件优化等方面。
一、索引优化索引是提高数据库查询效率的重要手段。
合理的索引设计能够极大地加快数据的查找速度,减少查询的IO操作。
在进行索引优化时,需要注意以下几个方面:1.选择正确的索引类型:MySQL提供了多种索引类型,包括B-Tree 索引、哈希索引、全文索引等。
在实际应用中,需要根据不同的场景选择合适的索引类型。
2.避免冗余索引:过多的冗余索引会增加数据库的存储空间和维护成本,同时也会降低数据库的更新性能。
因此,在设计索引时,需要避免创建冗余索引。
3.合理使用复合索引:复合索引可以减少物理文件的IO次数,提高查询效率。
但是,过长的复合索引会导致索引文件过大,影响查询性能。
因此,需要合理选择复合索引的列。
二、SQL语句优化SQL语句是操作MySQL数据库的核心,优化SQL语句能够显著提高数据库的查询性能。
在进行SQL语句优化时,需要注意以下几个方面:1.避免全表扫描:全表扫描是导致数据库性能低下的主要原因之一,尽量使用索引来加速查询,避免全表扫描。
2.避免使用SELECT *:SELECT *会查询所有的字段,包括不需要的字段,增加IO操作和网络传输的开销。
应该明确指定需要查询的字段。
3.使用合适的连接方式:在多表查询时,需要选择合适的连接方式,如内连接、外连接等。
同时,还需要使用JOIN语句替代子查询,提高查询效率。
三、配置优化正确的配置对于提高MySQL数据库性能非常重要。
下面是一些常见的配置优化技巧:1.合理配置缓冲区大小:通过调整缓冲区大小来提高MySQL的性能。
Mysql数据库千万级数据查询优化方案.....
Mysql数据库千万级数据查询优化⽅案.....⼀,Mysql数据库中⼀个表⾥有⼀千多万条数据,怎么快速的查出第900万条后的100条数据?怎么查,谁能告诉我答案?有没有⼈想着,不就⼀条语句搞定嘛select * from table limit 9000000,100;那我们试试,去执⾏下这个SQL看看吧看见了吗,查了100条数据⽤了7.063s。
这能算的上是快速查询吗,估计没⼈能接受了这种速度吧!基于这个问题,我今天就要说说⼤数据时的快速查询了。
⾸先,我演⽰下⼤数据分页查询,我的test表⾥有1000多万条数据,然后使⽤limit进⾏分页测试:select * from test limit 0,100;耗时:0.005sselect * from test limit 1000,100;耗时:0.006sselect * from test limit 10000,100;耗时:0.013sselect * from test limit 100000,100;耗时:0.104sselect * from test limit 500000,100;耗时:0.395sselect * from test limit 1000000,100;耗时:0.823sselect * from test limit 5000000,100;耗时:3.909sselect * from test limit 10000000,100;耗时:10.761s我们发现⼀个现象,分页查询越靠后查询越慢。
这也让我们得出⼀个结论:1,limit语句的查询时间与起始记录的位置成正⽐。
2,mysql的limit语句是很⽅便,但是对记录很多的表并不适合直接使⽤。
对⼤数据量limit分页性能优化说到查询优化,我们⾸先想到的肯定是使⽤索引。
利⽤了索引查询的语句中如果条件只包含了那个索引列,那在这种情况下查询速度就很快了。
因为利⽤索引查找有相应的优化算法,且数据就在查询索引上⾯,不⽤再去找相关的数据地址了,这样节省了很多时间。
MySQL批量千万级数据SQL插入性能优化细读
MySQL批量千万级数据SQL插⼊性能优化细读转⾃:https:///h330531987/article/details/76039795对于⼀些数据量较⼤的系统,⾯临的问题除了查询效率低下,还有就是数据⼊库时间长。
特别像报表系统,可能每天花费在数据导⼊上的时间就会长达⼏个⼩时之久。
因此,优化数据库插⼊性能是很有意义的。
⽹络上的⽜⼈很多,总会有⼀些⼿段可以提⾼insert效率,⼤家跟我⼀起分享⼀下吧:1. ⼀条SQL语句插⼊多条数据。
我们常⽤的插⼊语句⼤都是⼀条⼀个insert,如:1. INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)2. VALUES ('0', 'userid_0', 'content_0', 0);3. INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)4. VALUES ('1', 'userid_1', 'content_1', 1);现在我们将它修改成:1. INSERT INTO `insert_table` (`datetime`, `uid`, `content`, `type`)2. VALUES ('0', 'userid_0', 'content_0', 0), ('1', 'userid_1', 'content_1', 1);【数据对⽐】下⾯是⽹上⽜⼈提供⼀些对⽐数据,分别是进⾏单条数据的导⼊与转化成⼀条SQL语句进⾏导⼊,分别测试1百、1千、1万条数据记录。
通过对⽐,可以发现修改后的插⼊操作能够提⾼程序的插⼊效率。
Mysql limit 优化,百万至千万级快速分页
小小的索引+一点点的改动就使 mysql 可以支持百万甚至千万级的高效分页!
通过这里的例子,我反思了一点:对于大型系统,PHP 千万不能用框架,尤其是那种连
$strid.=$rs['id'].','; } $strid=substr($strid,0,strlen($strid)-1); //构造出 id 字符串 $db->pagesize=0; //很关键,在不注销类的情况下,将分页清空,这样只需要用一次数据 库连接,不需要再开; $db->execute("select id,title,url,sTime,gTime,vtype,tag from collect where id in ($strid)");
答案就是:复合索引! 有一次设计 mysql 索引的时候,无意中发现索引名字可以任取, 可以选择几个字段进来,这有什么用呢?开始的 select id from collect order by id limit 90000,10; 这么快就是因为走了索引,可是如果加了 where 就不走索引了。抱着试试看 的想法加了 search(vtype,id) 这样的索引。然后测试
sql 语句都看不到的框架!因为开始对于我的轻量级框架都差点崩溃!只适合小型应用 的快速开发,对于 ERP,OA,大型网站,数据层包括逻辑层的东西都不能用框架。如果 程序员失去了对 sql 语句的把控,那项目的风险将会成几何级数增加!尤其是用 mysql 的 时候,mysql 一定需要专业的 dba 才可以发挥他的最佳性能。一个索引所造成的性能差 别可能是上千倍!
MYSQL千万级数据量的优化方法积累
MYSQL千万级数据量的优化⽅法积累1.对查询进⾏优化,应尽量避免全表扫描,⾸先应考虑在 where 及 order by 涉及的列上建⽴索引。
2.应尽量避免在 where ⼦句中对字段进⾏ null 值判断,否则将导致引擎放弃使⽤索引⽽进⾏全表扫描,如:select id from t where num is null可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:select id from t where num=03.应尽量避免在 where ⼦句中使⽤!=或<>操作符,否则引擎将放弃使⽤索引⽽进⾏全表扫描。
4.应尽量避免在 where ⼦句中使⽤or 来连接条件,否则将导致引擎放弃使⽤索引⽽进⾏全表扫描,如:select id from t where num=10 or num=20可以这样查询:select id from t where num=10 union all select id from t where num=205.in 和 not in 也要慎⽤,否则会导致全表扫描,如:select id from t where num in(1,2,3) 对于连续的数值,能⽤ between 就不要⽤ in 了:select id from t where num between 1 and 36.下⾯的查询也将导致全表扫描:select id from t where name like ‘%李%’若要提⾼效率,可以考虑全⽂检索。
1. 如果在 where ⼦句中使⽤参数,也会导致全表扫描。
因为SQL只有在运⾏时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运⾏时;它必须在编译时进⾏选择。
然⽽,如果在编译时建⽴访问计划,变量的值还是未知的,因⽽⽆法作为索引选择的输⼊项。
如下⾯语句将进⾏全表扫描:select id from t where num=@num可以改为强制查询使⽤索引:select id from t with(index(索引名)) where num=@num8.应尽量避免在 where ⼦句中对字段进⾏表达式操作,这将导致引擎放弃使⽤索引⽽进⾏全表扫描。
MySQL千万级的大表要怎么优化(读写分离、水平拆分、垂直拆分)
MySQL千万级的大表要怎么优化(读写分离、水平拆分、垂直拆分)思考如何设计或优化千万级别的大表?此外无其他信息,个人觉得这个话题有点范,就只好简单说下该如何做,对于一个存储设计,必须考虑业务特点,收集的信息如下:1.数据的容量:1-3年内会大概多少条数据,每条数据大概多少字节;2.数据项:是否有大字段,那些字段的值是否经常被更新;3.数据查询SQL条件:哪些数据项的列名称经常出现在WHERE、GROUP BY、ORDER BY子句中等;4.数据更新类SQL条件:有多少列经常出现UPDATE或DELETE 的WHERE子句中;5.SQL量的统计比,如:SELECT:UPDATE+DELETE:INSERT=多少?6.预计大表及相关联的SQL,每天总的执行量在何数量级?7.表中的数据:更新为主的业务还是查询为主的业务?8.打算采用什么数据库物理服务器,以及数据库服务器架构?9.并发如何?10.存储引擎选择InnoDB还是MyISAM?大致明白以上10个问题,至于如何设计此类的大表,应该什么都清楚了!至于优化若是指创建好的表,不能变动表结构的话,那建议InnoDB引擎,多利用点内存,减轻磁盘IO负载,因为IO往往是数据库服务器的瓶颈另外对优化索引结构去解决性能问题的话,建议优先考虑修改类SQL语句,使他们更快些,不得已只靠索引组织结构的方式,当然此话前提是,索引已经创建的非常好,若是读为主,可以考虑打开query_cache,以及调整一些参数值:sort_buffer_size,read_buffer_size,read_rnd_buffer_size,join_buffer_size以及调整一些参数值:sort_buffer_size,read_buffer_size,read_rnd_buffer_size,join_buffer_size案列一我现在的公司有三张表,是5亿的数据,每天张表每天的增量是100w每张表大概在10个columns左右下面是我做的测试和对比1.首先看engine,在大数据量情况下,在没有做分区的情况下mysiam比innodb在只读的情况下,效率要高13%左右2.在做了partition之后,你可以去读一下mysql的官方文档,其实对于partition,专门是对myisam做的优化,对于innodb,所有的数据是存在ibdata 里面的,所以即使你可以看到schema变了,其实没有本质的变化在分区出于同一个physical disk下面的情况下,提升大概只有1%在分区在不同的physical disk下,我分到了三个不同的disks下,提升大概在3%,其实所谓的吞吐量,由很多因素决定的,比如你的explain parition时候可以看到,record在那一个分区,如果每个分区都有,其实本质上没有解决读的问题,这样只会提升写的效率。
记一次MySql千万级数据量单表按日分组查询平均值的优化遇到的各种问题
记⼀次MySql千万级数据量单表按⽇分组查询平均值的优化遇到
的各种问题
1、单表千万级数据量⼦查询 where in 要⽐ where exists 快(亲测查询时间差了100倍)
2、需要对datetime类型进⾏group by时(众所周知,函数不⾛索引),把⽇期的值拆分,⽐如要按⽇进⾏分组,拆分成年、⽉、⽇字段,类型分别⽤smallint、tinyint、tinyint,建⽴复合索引(Year,Month,Day)
3、数据量不⼤的临时表的存储引擎⽤engine=MEMORY ,优化效果很明显。
数据量太⼤的不建议,因为很吃内存,内存不够数据可能会丢失数据或者中断存储过程
4、truncate是先执⾏drop操作,然后再执⾏create操作,执⾏完成后会恢复初始的表空间。
(找资料时看到有⽂章说对于临时表要先truncate再drop,差点被坑死,故有此⼀记)
-------------------------------------------后续------------------------------------------------------
到⽣产环境给表加索引后,过了⼀晚数据库出故障⾃动关闭了。
正在查找原因。
原因⼤概找到了,有⼀个作业每10分钟跑⼀次,作⽤是从千万级数据量单表处查询数据然后插⼊到另⼀个表,这个作业跑⼀次耗时⼤于40分钟,跑到中途还报错退出了。
然后千万级数据量单表添加字段后也没有初始化好,添加索引的字段存在null值,导致死锁的发⽣。
不断被阻塞,最后导致mysql崩溃了。
- 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。