为什么要分表 当一张表的数据过多、数据文件过大时,会影响到数据的性能。将一张表拆分多张表是一个非常好办法。作为一个程序员,我希望有数据库能提供分表有如下几个功能: 1、自动分表 2、可自由拆分 3、可以跨磁盘存放 虽然我只一个程序员,了解并掌握这样的数据库技术会给我在写代码时多几条思路。
Mysql Merge分表 Mysql提供Merge存储引擎来进行分表,Merge表能将相同结构的表组合起来当做一张逻辑表来使用。代码如下:
create table t1(
id char(19) primary key,
uname varchar(255),
upassword varchar(255)
)ENGINE = MyISAM;
create table t2(
id char(19) primary key,
uname varchar(255),
upassword varchar(255)
)ENGINE = MyISAM;
create table test(
id char(19) primary key,
uname varchar(255),
upassword varchar(255)
)ENGINE = MERGE union(t1,t2) insert_method=last;
看上面代码,是不是觉得Merge有点与View相同,其实我也搞不清二者有什么区别,理论上分表还是使用Merge比较好,这也是官方推荐的方式。 使用Merge表有如下几个注意点: 1、所有分表都必须是MyISAM引擎,MyISAN引擎是不支持事务的。 2、Merge表只保证合表后数据唯一性,合表前的数据可能会存在重复。 3、删除分表正确的做法是 ALTER TABLE test UNION (t1); drop table t2;如果直接删除t2,test表会报错。 4、不能自动分表,需要定期维护。
编写自动分表脚本 在使用Merge表过程,最头痛的就是不能自动分表,靠人工定时清理肯定不合理的,在实践过程中,我想到了两种办法来解决这个问题。 第一、使用Mysql Event按时间周期自动建表 第二、分表到达一定数量后自动建表 具体实现思路如下: 首先模似Oracle数据库sequence
--创建自定义序列表
DROP TABLE IF EXISTS sequence;
CREATE TABLE sequence (
name VARCHAR(50) NOT NULL,
current_value INT NOT NULL,
increment INT NOT NULL DEFAULT 1,
PRIMARY KEY (name)
) ENGINE=InnoDB;
--定义取当前序列函数
DROP FUNCTION IF EXISTS currval;
CREATE FUNCTION currval (seq_name VARCHAR(50))
RETURNS INTEGER
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE value INTEGER;
SET value = 0;
SELECT current_value INTO value
FROM sequence
WHERE name = seq_name;
RETURN value;
END;
--定义取下一值函数
DROP FUNCTION IF EXISTS nextval;
CREATE FUNCTION nextval (seq_name VARCHAR(50))
RETURNS INTEGER
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
UPDATE sequence
SET current_value = current_value + increment
WHERE name = seq_name;
RETURN currval(seq_name);
END;
--定义更新值函数
DROP FUNCTION IF EXISTS setval;
CREATE FUNCTION setval (seq_name VARCHAR(50), value INTEGER)
RETURNS INTEGER
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
UPDATE sequence
SET current_value = value
WHERE name = seq_name;
RETURN currval(seq_name);
END;
再创建分表与Merge表
--创建第一张分表
create table t1(
id char(19) primary key,
uname varchar(255),
upassword varchar(255)
)ENGINE = MyISAM;
--创建merge表
drop table if EXISTS test;
create table test(
id char(19) primary key,
uname varchar(255),
upassword varchar(255)
)ENGINE = MERGE union(t1) insert_method=last;
--增加分表sequence
insert into sequence values('test',1,1);
针对Merge表创建一个增加数据存储过程testadd,这个过程的思路是第一次增加都查看当前表的数量,如果超过了20W,就创建一张新表,然后UNION到test表中。
drop PROCEDURE if EXISTS testadd;
create PROCEDURE testadd(uname varchar(255),upassword varchar(255))
BEGIN
DECLARE num INT;
DECLARE tname VARCHAR (255);
DECLARE i INT DEFAULT 1;
DECLARE uniontb VARCHAR (255) DEFAULT '';
insert into test values(UUID_SHORT(),uname,upassword);
SELECT count(*) INTO num FROM test;
IF MOD(num,200000) = 0 THEN
SET tname = CONCAT('t', nextval('test'));
set @sqlstr = CONCAT('create table ',tname,' like t1');
prepare stmt from @sqlstr;
EXECUTE stmt;
deallocate prepare stmt;
WHILE i <= currval ('test') DO
SET uniontb = CONCAT(uniontb, CONCAT('t', i), ',');
SET i = i + 1;
END WHILE;
set uniontb = LEFT(uniontb,LENGTH(uniontb) - 1);
set @sqlstr = CONCAT('ALTER TABLE test ENGINE = MERGE UNION = (',uniontb,') INSERT_METHOD = LAST');
prepare stmt from @sqlstr;
EXECUTE stmt;
deallocate prepare stmt;
END IF;
end
查看结果 100W自动分表插入 100W不分表插入 很明显,在使用自动分表存储过程后,数据插入性能下降很多。最佳办法是按周期建表
--创建分表
drop PROCEDURE if EXISTS createtb;
create PROCEDURE createtb()
BEGIN
DECLARE tname VARCHAR (255);
DECLARE i INT DEFAULT 1;
DECLARE uniontb VARCHAR (255) DEFAULT '';
SET tname = CONCAT('t', nextval('test'));
set @sqlstr = CONCAT('create table ',tname,' like t1');
prepare stmt from @sqlstr;
EXECUTE stmt;
deallocate prepare stmt;
WHILE i <= currval ('test') DO
SET uniontb = CONCAT(uniontb, CONCAT('t', i), ',');
SET i = i + 1;
END WHILE;
set uniontb = LEFT(uniontb,LENGTH(uniontb) - 1);
set @sqlstr = CONCAT('ALTER TABLE test ENGINE = MERGE UNION = (',uniontb,') INSERT_METHOD = LAST');
prepare stmt from @sqlstr;
EXECUTE stmt;
deallocate prepare stmt;
end
--创建事件
CREATE EVENT test_event
ON SCHEDULE
EVERY 1 DAY
STARTS date_add(date(curdate() + 1),interval 3 hour)
DO call createtb;
这两种办法都可以实现自动分表,具体情况可以具体使用。 测试自动分表 由于时间关系我先用了第一种分表办法
create PROCEDURE test()
begin
DECLARE i int DEFAULT 1;
while i < 5000000 DO
call testadd( CONCAT('test',i),'test' );
end while;
end;
结果如下: 一共25张表,每表20W数据