出发点
  比如,现在有这么一个问题,常见的一个面试题:
  有一张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>