Mysql优化6:分表/分区

1.1 分表/分区的概述
一个数据表可以存储很多记录信息,如果一个数据表存储的数据非常多,并且它的工作量(增删改查)非常多,负载(工作量)达到一定程度,会造成把表锁死的情况。

为了降低负载/工作量,可以给该表拆分为多个数据表。这样每个数据表的工作量会有所降低。分表/分区推荐使用myisam存储引擎。因为它会为每一个分表生成对应的数据文件(.MYD)和索引文件(.MYI)

例如我们要把Goods表拆分为Goods_1 。。。Goods_10,是个分表。

数据表拆分以后需要考虑到php如何操作这些表。那么有两种方式:
手动算法:需要在php语言里面设计代码逻辑,增加php代码工作量(不推荐)
mysql算法:php语言不需要做额外操作,是mysql分表/分区推荐的方法。

1.2 创建一个分表/分区的数据表
myisam和innodb都可以做分表设计,推荐是用myisam。
设计分区的字段需要是主键的一部分。

create table goods(
  id int not null auto_increment,
  name varchar(32) not null default ``,
  price int not null default `0`,
  primary key (id),
)engine=myisam charset=utf-8;
pritition by key(id) partitions 10;

现在给该表存放信息,信息会平均分摊到各个表中。

1.3 四种分表分区的算法
各种分区设计关联的字段必须是主键的一部分
或者是主键本身,或者是复合主键索引的从属主键一部分
求余:
key(); 根据指定的字段进行分区
partition by key(id) partitions 10;
hash(); 根据指定的表达式进行分区
partition by hash(month(pubdate)) partitions 12;
条件:
range(); 字段/表达式 符合某个条件范围的分区设计

    partition by range(year(pubdate))(
            partition    hou70    values    less    than(1980),
            partition    hou80    values    less    than(1990),
            partition    hou90    values    less    than(2000),
        )  

list(); 字段/表达式 符合某个列表范围的分区设计

partition by list(month(pubdate))(
            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),
        ) 

key()的分区算法:

create table goods(
  id int not null auto_increment,
  name varchar(32) not null default ``,
  price int not null default `0`,
  primary key (id),
)engine=myisam charset=utf-8;
partition by key(id) partitions 10;

hash()的分区算法:

create table goods(
  id int not null auto_increment,
  name varchar(32) not null default ``,
  price int not null default `0`,
  pubdate datetime not null default `0000-00-00`,
  primary key (id,pubdate),
)engine=myisam charset=utf-8;

partition by hash(month(pubdate)) partitions 12;#根据月份分区
range()的分区算法:

create table goods(
  id int not null auto_increment,
  name varchar(32) not null default ``,
  price int not null default `0`,
  pubdate datetime not null default `0000-00-00`,
  primary key (id,pubdate),
)engine=myisam charset=utf-8;
partition by range(year(pubdate))(
    partition hou70 values less than(1980),
    partition hou80 values less than(1990),
    partition hou90 values less than(2000),
)    #根据年份分区

list()的分区算法:

create table goods(
  id int not null auto_increment,
  name varchar(32) not null default ``,
  price int not null default `0`,
  pubdate datetime not null default `0000-00-00`,
  primary key (id,pubdate),
)engine=myisam charset=utf-8;
partition by list(month(pubdate))(
    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),
)    #根据季节分区

key():该方式区分不明显(不一定会严格平均分配数据),但是大方向明显。
hash();range();list():会根据业务特点把数据写入到对应的分区表里面
1.4 管理分区
增加、减少分区
1.4.1 求余(key、hash)算法管理
增加分区:

alter table goods add partition partitions 2;    #增加两个分区

减少分区:(减少分区时会丢失对应表中的数据)

alter table goods coalesce partition 2;    #减少两个分区

1.4.2 条件(range、list)算法管理
增加分区:

alter table goods add partition(
  partition  `分区名`  values  less  than [in](`常量/[列表]`),
  partition  `分区名`  values  less  than [in](`常量/[列表]`)
  ……
)

减少分区:(减少分区会丢失对应表中的数据)

alter table goods drop partition `分区名`

1.5 物理分表设计(老旧版本)
现要手动添加goods_1、goods_2……goods_5五张表;
要实现五张表平均分配数据:
情况一:
根据id获得一条信息,到指定的分表这个id对应的信息

$yu = $id%5;
$sql = "select * from goods_$ yu where id = $id";

上述方法可以根据指定的id取余获得指定的分表,进而操作对应的分表,实现平均操作分表。
情况二;
给指定的表写入指定的信息,但是不清楚要写入到哪一张表中,这时候我们需要一张辅助表记录每次插入的id,取这个辅助表中最大id值便知道操作的下一张表是哪一个。

$sql_fu = "insert into goods_fu values(null)";
$maxId = "select last_insert_id() from goods_fu ";
$yu = $maxId%5;$sql = "insert into goods_$yu values(...)";

1.6 慢查询日志
系统运行起来,内部需要执行许多sql语句。此时我们要把查询速度很慢的sql语句统计起来,并做优化设计。
设置一个时间阀值,超过该时间阀值得就把它当做慢的sql语句

show variables like `slow_query%`;

会看到以下结果:

Variable_name Value
slow_query_log OFF
slow_query_log_file 日志文件的完整路径

我们要打开日志,把slow_query_log值改成ON;
set global slow_query_log = 1;
日志打开了,现在来设置一个时间阀值:
首先,查看以下时间阀值:long_query_time

show variables like `long_query_time%`;

会看到以下结果:

Variable_name Value
long_query_time 10.000000

代表时间阀值为10秒,我们要把它改成2秒:
set long_query_time = 2;
成功将时间阀值改成2秒;
这时候凡是超过2秒的sql语句,会被记录到slow_query_log_file的路径里。再去优化这些语句吧!

你可能感兴趣的:(mysql,分区,个人笔记)