千万级别数据的mysql数据表优化
作者:网络转载 发布时间:[ 2016/7/27 10:20:00 ] 推荐标签:数据库 MySQL
出发点
比如,现在有这么一个问题,常见的一个面试题:
有一张users表,数据量在五千万以上,存在一条查询语句:
SELECT * FROM users WHERE name LIKE '%明%' AND sex='男' AND age=32 AND created_at BETWEEN 1388505600 AND 1420041600;
是说从users表中找出创建时间在14年到15年之间的年龄在32岁,名字中带有‘明’字的男性用户
追溯到数据表的设计,sql查询语句的调优,并且需要考虑到这种大表的数据插入时候的注意事项,数据分页及未来数据表管理时可能遇见的问题及解决方案
本文将会从存储层,设计层,sql语句层和架构层进行优化:
存储层 存储引擎的选取:
这里只展开InnoDB和MyIsam(选择哪个存储引擎需要判断当前的业务场景)
MyIsam表:
支持表级锁,锁的颗粒度比较大,所以被锁定的资源的争用情况会比其他的锁定级别会多,会降低并发处理的能力。 解决方法是可以设置 Concurrent Insert(并发插入)
在插入新的数据的时候,新数据会被追加到文件的末尾,但是当执行了update或delete等操作的时候,之前的数据的所在位置会没有内容。 这样,在数据的新增的时候速度相对会比较快
数据表的存储位置:在mysql安装目录/data/数据库名称下,分为数据表结构,数据表索引,数据表数据三个文件分别进行存储。这种索引和数据相分离,是通过物理地址进行关联的,这种索引结构也叫做‘非聚合型索引’,所以可以选择直接拷贝对应表的文件进行数据表的备份
支持数据表的压缩,牺牲数据表的更新操作,换取快速的查找速度。在CMD中执行myisamchk.exe -rq 表名。 使用命令myisamchk.exe --unpack 表名 进行解压缩。然后使用flush table 表名进行刷新数据表
支持全文索引
不支持外键
表的具体行数:保存有表的具体行数。在针对一个140万的数据表的时候,count(*)的速度很快:0.0003秒
总结:myisam是mysql为古老的存储引擎之一,对于以读为主的非事务性系统来说,myisam无疑是优先考虑的对象
InnoDB表
支持行级锁,带来的性能方面的锁好比较大,但是整体的并发性能却远远优于MyIsam表。但是如果使用不当可能会发生死锁,关于避免死锁的问题,并没有深入研究过,大体的发生死锁的原因是:由多个并发事务;每个事物都持有了锁;每个事务为了完成相关的逻辑都需要继续持有锁;多个事务之间产生加锁的循环等待->终形成死锁
支持外键,支持事务。
在进行select count(*)的时候,如果数据库中只存在一个primary key 的时候,执行count的时候速度会很慢,一张140万的数据表,执行的速度是6s多。但是myisam的count时间却只有0.00几秒。但是如果在InnoDB表中在添加一个索引的时候,速度会比较快。详情看:https://segmentfault.com/a/11...
数据表内容的存储位置:.frm文件用来存储表结构定义相关的元数据,表的索引和数据存放在一起。用户可以自定义,默认的初始化存储位置(windows)是在c:/programData/mysql 下。这种数据和索引存储在一个文件中的索引结构叫做‘聚合型’索引
字段的存储的类型的类型推荐:
字段应该优先选择 数值型进行存储,整形数据比起字符型处理的开销会更小,比如性别,是否这些可以使用enum进行存储。ip地址,时间等字段也存储成整形。可以使用数值型和枚举类型的字段进行不使用字符型进行存储
越小的数据类型越好。越小的数据类型在硬盘,cpu缓存和内存上的使用空间都更小,处理起来会更快
尽量避免使用null。在创建数据表的时候应该指定列为 NOT NULL ,然后设定默认值
设计层 适当的添加索引
添加索引可以增快数据查询的速度,但是对应的在数据的写入的时候需要去维护索引的数据,所以在数据的插入和更新等操作时速度回变慢。所以添加索引需要注意在常用的查询字段上面进行添加
这对于这里的需求来讲,创建一个name,age,created_at字段上的联合索引,在后面的查询条件的排列的地方先查询name字段,然后是age字段,然后created_at字段,后在是sex字段
具体的关于索引的内容可以看 https://segmentfault.com/a/11...
适时的进行分表和分区
分区
分区是将整个的业务模块分散到不同的服务器上进行存储,比如说用户模块,文章模块,相册模块等分别存在不同的服务器上完成分区
水平分表
物理分表:可以根据求余的方式或者hash或根据当前月份等方式进行
手动创建多个数据表,主要是根据当前记录的索引值进行判断该数据所在的位置
数据查询
<code>$id = $_GET['id'];
$mod = $id%5;
$sql = "SELECT * from goods_$mod WHERE id=$id";</code>
新增数据
//在新增数据的时候需要一张临时表去判断当前表中的大id值为多少,选择对应的数据存储的数据表
<code>$sql = "INSERT INTO `临时表` values null";
$new_id = "SELECT mysql_insert_id()";
$mod = $new_id%5;
$sql = "INSERT INTO goods_$mod VALUES ($new_id, 内容1, 内容2)";</code>
逻辑分表(严格上来讲,是在数据库的逻辑层进行分区)
为了保证分区时的查询效率,必须保证添加的分区字段为主键或unique key
在新建了分区之后,在查看数据表的存储文件的结构可以发现,数据表的索引和数据内容已经被单独拿出去存储了
key分区(求余)
<code> CREATE TABLE test_key(
id int not null auto_increment,
title varchar(32) not null default '',
price decimal(10,2) not null default 0,
created_at datetime not null,
PRIMARY KEY (id,created_at)
) engine=myisam charset=utf8
partition by key(id) partitions 5;</code>
1
hash分区(求余)
<code> CREATE TABLE test_hash(
id int not null auto_increment,
title varchar(32) not null default '',
price decimal(10,2) not null default 0,
created_at datetime not null ,
PRIMARY KEY (id,created_at)
) engine=myisam charset=utf8
partition by hash(month(created_at)) partitions 5;</code>
list分区(范围)
<code> CREATE TABLE test_list(
id int not null auto_increment,
title varchar(32) not null default '',
price decimal(10,2) not null default 0,
created_at datetime NOT NULL,
PRIMARY KEY (id,created_at)
) engine=myisam charset=utf8
partition by list(month(created_at))(
partition spring values in (3,4,5),
partition summer values in (6,7,8),
partition autumn values in (9,10,11),
partition winter values in (12,1,2)
);</code>
range分区(范围)
?
<code> CREATE TABLE test_list(
id int not null auto_increment,
title varchar(32) not null default '',
price decimal(10,2) not null default 0,
created_at datetime NOT NULL,
PRIMARY KEY (id,created_at)
) engine=myisam charset=utf8
partition by range(year(created_at))(
partition oldest values less than 1980,
partition old values less than 1990,
partition middle values less than 2010,
partition new values less than 2010
);</code>
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11