Mysql 创建存储过程、事件定时调用存储过程、表分区及自动分区学习笔记。


当一表数据逐渐变大后,查询会变得很慢,目前所用的是加索引和表分区,也可以做分表,这个暂时没用上


记录下对 已存在的表如何做分区: 


//(一般企业用会把这些过程写出sql脚本,丢服务器数据库跑一遍就ok了,还能留底)

对已存在的表做分区,我的做法(以时间为分区的情况):


   (1)创建数据结构相同的表, 命名: t_UserCopy
       创建表时先定义一个比最早时间早几年的分区,(其实无所谓,反正会删掉,后续补说明)
        源表t_user :
               id username password createTime
               1   程序猿     123456  2019-8-9 00:50
       创建t_userCopy
          

DROP TABLE IF EXISTS `t_UserCopy`;  
           CREATE TABLE `t_UserCopy`  (
                `Id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT ,
                `username` varchar(100)  NOT NULL ,
                `password` varchar(100) NOT NULL ,
                `createTime` datetime(0) NOT NULL,
                PRIMARY KEY (`Id`,`createTime`) USING BTREE,
                INDEX `index_createTime`(`createTime`) USING BTREE
            )PARTITION BY RANGE (Year(createTime))  
             (
             Partition p2010  Values Less Than ( Year('2011-01-01') )
            );


        注:我这是按年分,数据多可以按月
        
        分区限制:
            •   最大分区数目不能超过1024 >> 按年分能分85年足够了,一般数据过多直接分表了
            
            •   如果含有唯一索引或者主键,则分区列必须包含在所有的唯一索引或者主键在内 >>
                PRIMARY KEY (`Id`,`createTime`) USING BTREE, 所以要这样定义主键。至于为什么2010后要定义2011年-01-01呢,ess Than 嘛,顺带学学sql语法
                
            •   不支持外键,既独立表,不能有外键
            
    
    
    (2)循环创建表分区
            A:插入数据前先做好分区,按年分的话,例如表数据creatTime最早为2017年,那就创建17到2019或2020都行,
                我是创建到未来一年,保障点。天知道服务器会不会挂掉重启啥的。
            
            B :在(1)中我们创建了一个p2010的分区,假设我们的t_User  称源表,最早时间为2017年至今,
            手动创建不够懒啊,遂:在"存储过程" 中循环对 添加 最早时间 至 未来一年的 分区,用 whiLe 循环创建分区,简单粗暴

  DECLARE v_i INT DEFAULT 0;
                 -- 获取告警最小年份
                Select Year(Min(createTime)) Into @min_Year From t_User;
                -- 分区至未来 1年
                Set v_Count = Year(now()) - @min_Year + 2;
                While v_i < v_Count DO
                    Set v_Year = @min_Year + v_i;
                    Set v_Sql = CONCAT('Alter Table t_UserCopy Add Partition (Partition P', Cast( v_Year As Char(4)),
                        ' Values Less Than (', Cast((v_Year + 1) As Char(4)), '))');
                    Set @Sql = v_Sql;
                    Prepare Cmd From @Sql;
                    Execute Cmd;
                    Deallocate Prepare Cmd;
                    Set v_i = v_i + 1;
                End While;


            注:若年份大于分区年份,则会报错,因为他不符合你所创建的分区,对号入座,没座位干等就给你打小报告啦
        
                
                    
     
     (3) 复源表数据(t_User)到分区表(t_UserCopy),删源表,重命名分区表 

     INSERT into t_UserCopy SELECT * FROM t_User;
     DROP TABLE IF EXISTS `t_User`;  
     ALTER TABLE t_UserCopy RENAME TO t_User;

        注:1:必须在创建了对应的分区后再复制源表数据,住酒店得先预定嘛
        
           2:更新期间产生的数据咋办呢,上级是停服务器搞的,所以我只负责写脚本~但我认为不太好,对于工业上的来说,
            一些监控上的告警不会因为你停服务器而不发生告警,即使在夜深人静的时候也可能告警,
            停服务器就会丢失数据,虽然一两分钟就能跑完脚本~
            想法: A 借助第三方车轮 B...求助大佬

 

    (4) 删除最初分区

-- 删除最初固定分区
Alter table t_UserCopy drop partition p2010;

            :最初分区是为了创建分区表而用,因创建分区表至少要有一个,那就先创建一个再删了就好,(给东家一个面子嘛)
                删了无用的分区出于...you konw that    

            
    -------------------------- 至此分区的创建及数据的复原已搞定,可时间不等人啊,来个自动分区吧-----------------------------------
            
    (5) 自动创建分区(event事件)
                还是懒,不想每年都给它加一个分区吧,来个自动加分区吧,那就用到 event,即事件,定时调用存储过程
                这里我让其每个月执行一次,看未来一年的分区是否存在,不存在则添加,存在就:"打扰了大哥,但我下个月还来"。
                这是为了减少意外,一年12次都出意外无法执行event的概率极底。

     Drop EVENT IF EXISTS `e_createTimePartition_year`; 
            DELIMITER ;;
            CREATE EVENT IF NOT EXISTS e_createTimePartition_year 
                ON SCHEDULE Every 1 Year STARTS DATE_ADD(DATE_ADD(CURDATE(), INTERVAL 1 Year),INTERVAL 9 HOUR)
                ON COMPLETION PRESERVE
                DO 
                Call spAppendPartition_t_User(); 
                ;;

                
            注: 1: ON SCHEDULE Every 1 Year STARTS DATE_ADD(DATE_ADD(CURDATE(), INTERVAL 1 Year),INTERVAL 9 HOUR)
                    是每年分一次,这个是我最初的版本,后改用每月1号00:00执行,(拖了一个月才来记录的(●'◡'●))
                    又拖了几天: 加个每月1号凌晨执行的定时时间
                    ON SCHEDULE Every 1 Month STARTS DATE_ADD(DATE_ADD(DATE_SUB(CURDATE(),INTERVAL DAY(CURDATE())-1 DAY), INTERVAL 1 MONTH),INTERVAL 0 HOUR)
                2: 分区前得先判断是否存在分区                    

  -- 未来一年
                    Set v_Year = Year(now()) + 2;
                    
                    -- 若分区已经存在
                    If Exists (t_User
                            Select * From 
                                (
                                    Select Cast(PARTITION_DESCRIPTION As Unsigned Int) As TimeCode From information_schema.`PARTITIONS` 
                                    Where 
                                        TABLE_SCHEMA = Database() And Lower(Table_Name) = Lower('') 
                                ) t
                            Where t.TimeCode >= v_Year
                        ) Then 
                        
                        Select CONCAT('p',v_Year) as '分区已经存在';
                        Leave Label_Start;
                    End If;

        
            


    (6) 测试自动分区是否能按预期进行:(服务器测试)
         一年一次测试的话,一年一年的等就行了,到了明年这个时候来看看,如果你还记得起来的话
         So, 在测试服务器上测试,按年的话,上述语法是今天到明年的今天的早时9点,直接去服务器改到明年今天8:59:50
         坐等10秒后,查看表分区:

 Select PARTITION_NAME  From INFORMATION_SCHEMA.PARTITIONS 
         Where TABLE_SCHEMA=Database() And TABLE_NAME = t_User

         伸手党: 
                修改时间: date -s '20xx-xxchu'fa-xx 08:59:50' 
                查看数据库时间是否修改成功: mysql> select now();
                重置时间:  hwclock  --hctosys                //设置系统时间和硬件时间同步
         



    (8)整合上述的完整脚本,后续再更吧
      

             附上用得上的mysql 查询:     

   -- 查询所有数据库event事件
        select * from mysql.event WHERE db = '数据库名称';

        -- 查看分区
        SELECT PARTITION_NAME,TABLE_ROWS,PARTITION_EXPRESSION,PARTITION_DESCRIPTION, Table_Name FROM INFORMATION_SCHEMA.PARTITIONS 
        WHERE TABLE_SCHEMA= DATABASE()  AND TABLE_NAME = 'AlarmEvent'; 


        -- 分区查询
        Select AlarmDateTime From AlarmEvent Partition(p2019);

        -- 删除指定分区
        alter table AlarmEvent drop partition p2023;

 

 

参考文章: https://www.cnblogs.com/zhouguowei/p/9360136.html    

Last: 转载请附上作者,码字不易呀~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章