1. 程式人生 > >SQLServer、Mysql、Oracle資料庫分割槽方案參考

SQLServer、Mysql、Oracle資料庫分割槽方案參考

第一部分:SQLServer分割槽表相關

SQLServer表分割槽比較特殊,表分割槽需要將索引列關聯到分割槽方案,分割槽方案又需要依賴分割槽函式來劃分資料到檔案組,而一個檔案組又可以包含多個檔案。所以一個合理的SQLServer分割槽,需要自行創檔案組、檔案、分割槽函式和分割槽方案。以下給出相關的參考SQL以及按月分割槽例項

  • 檔案檔案組相關
-- 建立儲存檔案的資料夾,按年儲存,按月分割槽
exec sys.xp_create_subdir 'D:\SQLServerDATA\E_TD\2018';
-- 建立檔案組
ALTER DATABASE acrossprovince ADD FILEGROUP [E_TD_2018];
-- 刪除檔案組
ALTER DATABASE acrossprovince REMOVE FILEGROUP E_TD_2018;
-- 檢視檔案組資訊
select * from sys.filegroups where name='E_TD_2018';
-- 建立檔案
IF NOT EXISTS(select 1 from sys.database_files where name='E_TD_201810')
	ALTER DATABASE acrossprovince ADD FILE ( NAME = N'E_TD_201810', FILENAME = N'D:\SQLServerAcrossProvince\E_TD\2018\E_TD_201810.ndf',SIZE = 5mb,FILEGROWTH = 5mb) TO FILEGROUP [E_TD_2018]
GO
-- 刪除檔案
ALTER DATABASE acrossprovince REMOVE FILE E_TD_201810;
-- 檢視檔案資訊
select * from sys.database_files; 
  • 分割槽方案和分割槽函式相關
-- 刪除分割槽方案
IF EXISTS(SELECT 1 from sys.partition_schemes where name='E_TD_PS') DROP PARTITION SCHEME  E_TD_PS
GO
-- 刪除分割槽函式
IF EXISTS(SELECT 1 FROM sys.partition_functions where name='E_TD_PF') DROP PARTITION FUNCTION E_TD_PF
GO
-- 建立分割槽函式,該函式建立的年份應該是很久遠的入到primary庫的資料
create PARTITION function E_TD_PF(datetime)
as range left for values('2017/01/01')
GO
-- 建立分割槽方案,初始資料存入PRIMARY檔案組,後續通過變更分割槽來更改檔案儲存資訊
CREATE PARTITION SCHEME E_TD_PS AS PARTITION E_TD_PF ALL TO (
	[PRIMARY]
);
GO
-- 修改分割槽方案和分割槽函式
alter partition scheme E_TD_PS next used [E_TD_201701]
alter partition function  E_TD_PF() split range('2017/02/01')
  • 表相關
CREATE TABLE [dbo].[E_TD](
	[id] [varchar](37) NOT NULL,
	[createTime] [datetime] NOT NULL,
	[backup7] [varchar](50) NULL,
	[backup8] [varchar](50) NULL,
	[backup9] [varchar](50) NULL,
	[backup10] [varchar](50) NULL,
PRIMARY KEY CLUSTERED
(
	[id] ASC,
	[createTime] ASC
)) ON E_TD_PS(createTime)
GO
  • 分割槽例項:建立分割槽表,並建立一次性建立一年12個月分割槽的儲存過程,該儲存過程可以每年12月1日執行一次從而達到自動分割槽
-- 建立分割槽函式,該函式建立的年份應該是很久遠的入到primary庫的資料
create PARTITION function E_TD_PF(datetime)
as range left for values('2017/01/01')
GO
-- 建立分割槽方案,初始資料存入PRIMARY檔案組,後續通過變更分割槽來更改檔案儲存資訊
CREATE PARTITION SCHEME E_TD_PS AS PARTITION E_TD_PF ALL TO (
	[PRIMARY]
);
GO
-- 建立表,應用上述的分割槽方案,分割槽欄位必須是索引欄位
CREATE TABLE [dbo].[E_TD](
	[id] [varchar](37) NOT NULL,
	[createTime] [datetime] NOT NULL,
	[backup8] [varchar](50) NULL,
	[backup9] [varchar](50) NULL,
	[backup10] [varchar](50) NULL,
PRIMARY KEY CLUSTERED
(
	[id] ASC,
	[createTime] ASC
)) ON E_TD_PS(createTime)
GO

-- SQLServer函式:根據表名和指定年份,一次建立指定表一年的分割槽表,一個月一個分割槽
IF EXISTS(select 1 from sys.objects where name='CREATE_PARTITION')
	drop proc CREATE_PARTITION
GO

CREATE proc CREATE_PARTITION
	@v_tablename varchar(100),@v_year int
AS

BEGIN
	DECLARE
	@v_year_str varchar(6),
	@v_ymonth varchar(32),
	@v_curdate date,
	@v_i int,
	@v_root_data_dir varchar(100),
	@v_data_dir varchar(100),
	@v_dynamic_sql varchar(4000);

	SET @v_tablename = UPPER(@v_tablename);
	SET @v_year_str = CONVERT(varchar(6),@v_year);
	SET @v_curdate = CONVERT(date,@v_year_str+'/01/01',111);
	SET @v_i = 1;
	SET @v_root_data_dir = 'D:\SQLServerAcrossProvince';
	SET @v_data_dir = @v_root_data_dir+'\'[email protected]_tablename+'\'[email protected]_year_str;

	-- 建立存放檔案的子路徑,每年一個,該儲存過程可以多次呼叫
	exec sys.xp_create_subdir @v_data_dir;

	while @v_i<=12
		BEGIN
			SET @v_ymonth = CONVERT(varchar(6), @v_curdate, 112);
			-- 一個檔案組一個檔案,如果檔案組存在,則檔案也存在
			IF NOT EXISTS(select 1 from sys.filegroups where [email protected]_tablename+'_'[email protected]_ymonth)
				BEGIN
					-- 建立檔案組和檔案
					SET @v_dynamic_sql='ALTER DATABASE acrossprovince ADD FILEGROUP ['[email protected]_tablename+'_'[email protected]_ymonth+']'
					EXEC(@v_dynamic_sql)
					SET @v_dynamic_sql='ALTER DATABASE acrossprovince ADD FILE ( NAME = N'''[email protected]_tablename+'_'[email protected]_ymonth+''', FILENAME = N'''[email protected]_root_data_dir+'\'[email protected]_tablename+'\'[email protected]_year_str+'\'[email protected]_tablename+'_'[email protected]_ymonth+'.ndf'',SIZE = 5mb,FILEGROWTH = 5mb) TO FILEGROUP ['[email protected]_tablename+'_'[email protected]_ymonth+']'
					EXEC(@v_dynamic_sql)
					-- 使用對檔案組和檔案進行應用,先改方案,再改函式
					SET @v_dynamic_sql='alter partition scheme '[email protected]_tablename+'_PS next used ['[email protected]_tablename+'_'[email protected]_ymonth+']'
					EXEC(@v_dynamic_sql)
					SET @v_dynamic_sql = 'alter partition function  '[email protected]_tablename+'_PF() split range('''+CONVERT(varchar(32),DATEADD(MONTH,1,@v_curdate),111)+''')'
					EXEC(@v_dynamic_sql)
				END
			SET @[email protected]_i+1
			SET @v_curdate = DATEADD(MONTH,1,@v_curdate)
		END


END

第二部分:Mysql分割槽

mysql分割槽不如SQLServer分割槽複雜,以下直接給例項SQL參考

  • 分割槽例項
-- 建立分割槽表
DROP TABLE IF EXISTS E_TD;
CREATE TABLE `E_TD` (
  `id` varchar(37) NOT NULL,
  `createTime` datetime(3),
  `backup1` varchar(50),
  `backup9` varchar(50),
  `backup10` varchar(50),
  PRIMARY KEY (`id`,createTime)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
partition by range(TO_DAYS(createTime))(
	partition E_TD_20181001 values less than (to_days('2018-11-01')),
	partition E_TD_20181101 values less than (to_days('2018-12-01'))
);
-- 建立分割槽儲存過程,該儲存過程接收表名,開始日期,結束日期引數,然後根據引數建立開始日期所屬月份到結束日期所屬月份的下一個月的表分割槽。
-- 此儲存過程可以每月或每年執行一次從而達到自動分割槽
DROP PROCEDURE IF EXISTS create_partition;
create PROCEDURE create_partition(in_tabName VARCHAR(68),in_startDate DATE,in_endDate date)
	COMMENT '為表增加分割槽,改分割槽為rang分割槽,範圍為一個月一個分割槽,引數為:表名,開始日期,結束日期'
BEGIN
    DECLARE maxpdate int DEFAULT 0;
    DECLARE i date;
    DECLARE var_cou int DEFAULT 0;
    first_lable:BEGIN
    SET var_cou=0;

  	-- 檢視當前表是否是分割槽表
    SELECT COUNT(*) INTO var_cou
    FROM INFORMATION_SCHEMA.PARTITIONS
    WHERE `table_name`=in_tabName ;

    IF var_cou =0 THEN
        SELECT CONCAT(in_tabName,'  該表不是分割槽表,不能進行新增操作');
        LEAVE first_lable;
    END IF;

		-- 清洗引數,將in_startDate和in_endDate轉換為當月第一天,且把endDate多加一個月
		set in_startDate=CONCAT(DATE_FORMAT(in_startDate,'%Y-%m'),'-01');
		set i=in_startDate;
		set in_endDate=DATE_ADD(CONCAT(DATE_FORMAT(in_endDate,'%Y-%m'),'-01'),INTERVAL 1 MONTH);
    WHILE i<=in_endDate do
        -- 查詢當前分割槽表是否存在
        SELECT count(*) INTO maxpdate
        FROM INFORMATION_SCHEMA.PARTITIONS
        WHERE `table_name`=in_tabName and RIGHT(PARTITION_NAME,8)=DATE_FORMAT(i,'%Y%m%d');
       if maxpdate =0 then

          set @sqlStat1=concat('alter table ',in_tabName,' add partition (partition ',in_tabName,'_',DATE_FORMAT(i,'%Y%m%d'),' values less than(');
				  set @sqlStat=concat(@sqlStat1,TO_DAYS(DATE_ADD(i,INTERVAL 1 MONTH)),'))');
          PREPARE stmt FROM @sqlStat;
          SELECT @sqlStat;
          EXECUTE stmt;
          DEALLOCATE PREPARE stmt;
       end if;
       set i = date_add(i, interval 1 month);

    end while;
  END first_lable;
end

第三部分:Oracle分割槽

oracle分割槽類似mysql分割槽,比較簡單,以下直接給出例項參考SQL

  • 分割槽例項
CREATE TABLE "E_TD" (
  "id" VARCHAR2(37) NOT NULL ,
  "createTime" date NOT NULL ,
  "backup1" VARCHAR2(50) DEFAULT NULL ,
  "backup2" VARCHAR2(50) DEFAULT NULL ,
  "backup10" VARCHAR2(50) DEFAULT NULL ,
  PRIMARY KEY ("id","createTime")
)
PARTITION BY range("createTime")
(
	partition ETCTS_TD_NONCASH_RESU_20181001	values less than(to_date('20181101','YYYYMMDD')),
	partition ETCTS_TD_NONCASH_RESU_20181101	values less than(to_date('20181201','YYYYMMDD'))
);
-- 建立分割槽儲存過程,該儲存過程接收表名,開始日期,結束日期引數,然後根據引數建立開始日期所屬月份到結束日期所屬月份的下一個月的表分割槽。
-- 此儲存過程可以每月或每年執行一次從而達到自動分割槽
CREATE OR REPLACE
PROCEDURE CREATE_PARTITION(in_tabName in VARCHAR2,i_startDate in DATE,i_endDate in DATE)
	AS
	maxpdate int :=0;
	i date;
	var_cou int :=0;
	sqlStatl VARCHAR2(4000);
	in_startDate date:=TO_DATE(TO_CHAR(i_startDate,'YYYYMM')||'01','YYYYMMDD');
	in_endDate date:=ADD_MONTHS(TO_DATE(TO_CHAR(i_endDate,'YYYYMM')||'01','YYYYMMDD'),1);
BEGIN
	var_cou:=0;
	i:=in_startDate;
	-- 檢視當前表是否是分割槽表
	SELECT COUNT(1) INTO var_cou FROM USER_TAB_PARTITIONS WHERE TABLE_NAME=in_tabName;
	IF var_cou =0 THEN
		-- dbms_output.put_line(in_tabName||'  該表不是分割槽表,不能進行新增操作');
		return;
	END IF;WHILE(i<=in_endDate)
		LOOP
			SELECT count(1) INTO maxpdate FROM USER_TAB_PARTITIONS WHERE TABLE_NAME=in_tabName and SUBSTR(PARTITION_NAME,-8)=to_char(i,'YYYYMMDD');IF maxpdate=0 then
				-- dbms_output.put_line('alter table '||in_tabName||' add partition '||SUBSTR(in_tabName,0,21)||'_'||to_char(i,'YYYYMMDD')||' values less than(to_date('''||to_char(i,'YYYYMMDD')||''',''YYYYMMDD''))');
				EXECUTE immediate 'alter table '||in_tabName||' add partition '||SUBSTR(in_tabName,0,21)||'_'||to_char(i,'YYYYMMDD')||' values less than(to_date('''||to_char(ADD_MONTHS(i,1),'YYYYMMDD')||''',''YYYYMMDD''))';END IF;i:=ADD_MONTHS(i,1);END LOOP;END;