由于存储数据量太大,当一个表超过 1000w 的数据时 MySQL 性能会逐渐下降,对数据操作时非常耗时,为了优化数据库性能,使用了分表的方式每个月对数据实现水平分割,也就是说每月自动生成表一张表。
CREATE DEFINER=`root`@`%` PROCEDURE `auto_create_month_table`(
IN `database_name` VARCHAR(50),
IN `table_name` VARCHAR(50)
)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT '每月自动生成表一张表'
BEGIN
-- 声明变量
DECLARE old_table_name VARCHAR(128);
DECLARE new_table_name VARCHAR(128);
DECLARE done INT DEFAULT 0;
-- 声明游标
DECLARE table_cursor CURSOR FOR SELECT TABLE_NAME FROM `information_schema`.`TABLES` WHERE TABLE_SCHEMA = database_name AND TABLE_NAME = table_name;
-- 如果没有数据返回或者 select 出现异常,程序继续,并将变量 done 设为 1
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
-- 打开游标
OPEN table_cursor;
-- 遍历游标
REPEAT
-- 获取当前游标指针记录,使用 fetch 来取出数据,取出值赋给自定义的变量
FETCH table_cursor INTO old_table_name;
IF NOT done THEN
-- 真正要操作的需求
SELECT concat(table_name,'_',DATE_FORMAT(DATE_ADD(CURDATE(),INTERVAL 1 MONTH), '%Y%m')) INTO new_table_name;
SET @sql_cmd = CONCAT('create table if not exists `',new_table_name,'` like `' , old_table_name,'`');
-- 如果需要变量返回,使用 select,如:select 变量名
-- SELECT @sql_cmd;
-- 预定义一个语句,并将它赋给 pre_stmt
PREPARE pre_stmt FROM @sql_cmd;
-- 执行语句,存储过程如果有参数,后面加参数格式为:@参数名=value,也可直接为参数值value,如果 pre_stmt 不存在,将会引发一个错误
EXECUTE pre_stmt;
-- 释放一个预定义语句的资源
DEALLOCATE PREPARE pre_stmt;
END IF ;
-- 根据 done 判断是否结束
UNTIL done END REPEAT;
-- 关闭游标
CLOSE table_cursor;
END
存储过程名称为 auto_create_month_table,参数分别为:database_name,table_name。
调用存储过程
CALL `auto_create_month_table`('test', 'temp_bigint');
注意
执行存储过程时出现一下异常
the user specified as a definer ('root'@'%') does not exist
此问题是权限问题,操作存储过程的用户不存在,授权权限即可。
添加 root 权限
grant all privileges on *.* to root@"%" identified by ".";
刷新权限
flush privileges;
declare {变量} {数据类型}
声明变量使用 declare 命令,变量必须先声明后使用。变量是有作用域的,作用范围在 begin 与end 中使用。
default 参数的默认值。如果定义了默认值,不必指定该参数的值即可执行过程。
set {变量名=表达式}
-- 或
sel select{变量名=表达式}
declare 和 set 区别
游标是一个存储在MySQL服务器上的数据库查询,它不是一条 selec t语句,而是被该语句所检索出来的结果集。
定义游标
DECLARE table_cursor CURSOR FOR SELECT TABLE_NAME FROM `information_schema`.`TABLES` WHERE TABLE_SCHEMA = database_name AND TABLE_NAME = table_name;
查询 `information_schema`.`TABLES` 表的 table_name 作为游标.
有时候,不希望存储过程抛出错误中止执行,而是希望返回一个错误码。 可以通过定义 continue/exit 异常处理的 handler 来捕获 sqlwarning/not found/sqlexception (警告/无数据/其他异常)。
for 后面可以改为 sqlwarning, not found, sqlexception 来指示所有异常都处理,当不进行异常处理时,以下代码将直接抛出一个 error 1062 (23000) 。
例:
declare continue handler for sqlstate '02000' set done = 1;
定义 continue/exit 异常处理的 handler 来捕获 sqlstate,避免抛出错误,定义一个返回参数 done 赋予特殊值来表示失败,可以通过获取返回值而不是捕获异常的方式来处理业务逻辑。
'02000' 代表发生下述异常之一:
当 fetch 游标到了数据库表格最后一行的时候,设置 done=1。
变量需要返回,可以使用select语音,如:select 变量名
优点:
缺点: