当前位置: 首页 > 科技观察

如何对千万级数据的MySQL表进行优化

时间:2023-03-20 19:14:41 科技观察

MySQL为了提高性能,将表索引加载到内存中。但是当表中的数据达到一定数量时,内存无法存储这些索引,索引也无法存储,只能进行磁盘IO,导致性能下降。实际调优我这里有一张表,数据1000w,目前只有一个主键索引CREATETABLE`user`(`id`int(10)NOTNULLAUTO_INCREMENT,`uname`varchar(20)DEFAULTNULLCOMMENT'account',`pwd`varchar(20)DEFAULTNULLCOMMENT'密码',`addr`varchar(80)DEFAULTNULLCOMMENT'地址',`tel`varchar(20)DEFAULTNULLCOMMENT'电话',`regtime`char(30)DEFAULTNULLCOMMENT'注册时间',`age`int(11)DEFAULTNULLCOMMENT'age',PRIMARYKEY(`id`))ENGINE=InnoDBAUTO_INCREMENT=10000003DEFAULTCHARSET=utf8;查询所有关于16s的信息。可以说是相当缓慢了。通常我们有一个后台系统,比如这是一个电商平台,这是一个用户表。后台管理系统一般会查询这些用户信息,并进行一些操作,比如直接在后台添加用户,或者删除用户。所以这里有两个需求,一个是查询计数,一个是分页查询。下面分别测试一下count和分页查询所用的时间。0.35sselect*fromuserlimit5000000,10//1.7sselect*fromuserlimit9000000,10//2.8sselectcount(1)fromuser//1.7s从上面查询耗时可以看出,如果是分页查询,查询越多后面用的数据很长,查询计数也需要1.7s。这显然不符合我们的要求。所以,这里我们需要优化一下。首先,让我们尝试优化这里的索引。首先我们看一下只有主键索引的执行计划:altertable`user`addINDEX`sindex`(`uname`,`pwd`,`addr`,`tel`,`regtime`,`age`)看上面的执行计划,虽然类型从all->index变成了sindex,但是实际查询速度并没有改变。其实创建联合索引是为了让条件查询更快,不是全表查询select*fromuserwhereuname='6.445329111484186'//3.5s(没有联合索引)select*fromuserwhereuname='6.445329111484186'//0.003s(有ajointindex)所以这就是有联合索引和没有索引的区别这里基本可以证明,加不加索引,全表查询的时候,效率会很慢,因为结果是索引已经不好用了,那就只能另寻他法了。按照我之前面试mysql的时候说的,count可以单独存在一个表中。11)NOTNULLCOMMENT'表总数据',PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8COLLATE=utf8_bin;在这里跟大家说一下,这种表一般不会查全部,只查一个,所以建表的时候可以建hashselectformcountfromattributewhereformname='user'//在几乎不用的时候优化count。如果有上面的选择条件,可以建立索引,通过索引过滤进行查询,这样就不需要读取count了。那么,计数是没有问题的,如何优化分页查询优化呢?这里可以使用子查询来优化select*fromuserwhereid>=(selectidfromuserlimit9000000,1)limit10//1.7s其实子查询是这样写的,判断id,其实就是通过覆盖索引来查询。效率会大大提高。但是,我这里的测试是1.7s。以前公司优化这方面的时候,是低于这个查询时间的。您也可以自己生成数据并进行测试。但是如果数据量太大,我还是推荐使用es或者一些默认的。选择、计数可以单独列出。至此,一个千万级数据分页查询的优化就完成了。