sql server:
1:首先我們創建test1數據庫和shop表
2:創建文件組和文件
3:創建分區
①:右鍵Shop表,彈出菜單中選擇 “存儲” => "創建分區"
②:創建“分區函數”名 和 “分區方案”名。
③:創建分區映射,也就是將”分區函數“和“文件組”進行關聯。
④: 最後我們可以看一下界面給我生成的分區函數以及分區方案,蠻有意思的。
1 USE [Test1]
2 GO
3 BEGIN TRANSACTION
4 CREATE PARTITION FUNCTION [MyRangeCreatTime](datetime) AS RANGE LEFT FOR VALUES (N'2012-12-31T00:00:00', N'2013-12-31T00:00:00', N'2014-12-31T00:00:00')
5
6
7 CREATE PARTITION SCHEME [MySchemeCreateTime] AS PARTITION [MyRangeCreatTime] TO ([Before2013], [T2013], [T2014], [After2014])
8
9
10 ALTER TABLE [dbo].[Shop] DROP CONSTRAINT [PK__Shop__3214EC277F60ED59]
11
12
13 ALTER TABLE [dbo].[Shop] ADD PRIMARY KEY NONCLUSTERED
14 (
15 [ID] ASC
16 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
17
18
19 CREATE CLUSTERED INDEX [ClusteredIndex_on_MySchemeCreateTime_635288828144372217] ON [dbo].[Shop]
20 (
21 [CreateTime]
22 )WITH (SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [MySchemeCreateTime]([CreateTime])
23
24
25 DROP INDEX [ClusteredIndex_on_MySchemeCreateTime_635288828144372217] ON [dbo].[Shop] WITH ( ONLINE = OFF )
26
27
28
29
30 COMMIT TRANSACTION
從圖中可以看到生成好的分區函數名”[MyRangeCreatTime]“ 和分區架構名“[MySchemeCreateTime]”,最後我們執行下該sql就ok了。
⑤ 插入測試數據並進行簡單的測試
這裏測試下“2013-1-1”是在哪個分區下。
總結一下可能用到的所有sql語句:
1,新建默認的 filegroup
alter database Test add filegroup Before2013
2, 新建默認的 file
alter database Test add file
(Name=N'Before2013',filename='D:\Program Files\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQL\DATA\Before20131.ndf',size=5mb,maxsize=100Mb,filegrowth=5mb)
to filegroup Before2013
3,新建分區函數
create partition function RangeTime (datetime) as range left for values ('2012-12-31','2013-12-31','2014-12-31')
4,新建分區方案
create partition scheme RangeSchema_CreateTime as partition RangeTime to (before2013,T2013,T2014,after2014)
5,新建表
create table equipment_n
(
[dataId] [int] NOT NULL,
[operaDate] datetime NULL,
[eqId] [int] NULL,
[l1] [varchar](30) NULL,
[l2] [varchar](30) NULL,
[lc] [varchar](30) NULL,
) on RangeSchema_CreateTime(operaDate)
6, 自動添加數據
declare @i int
set @i = 4
while @i < 1000
begin insert into equipment_n ([operaDate]
,[eqId]
,[l1]
,[l2]
,[lc]) values(dateadd(dd,datediff(dd,'2012-01-01','2015-01-30')*RAND(),'2012-01-01'),1,@i+1,@i+2,@i+3)
set @i = @i +1
end
7, 查詢分區表中數據分佈情況
select $partition.RangeTime(operaDate) as number, COUNT(*) as count
from equipment_n group by $partition.RangeTime(operaDate)
8, 設置自增ID
alter table equipment_n drop column dataId alter table equipment_n add dataId int identity(1,1)
ALTER TABLE dbo.equipment_n ADD CONSTRAINT
PK_equipment_n PRIMARY KEY NONCLUSTERED
(
dataId
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
9, 定製計劃
DECLARE @maxValue INT,
@secondMaxValue INT,
@differ INT,
@fileGroupName VARCHAR(200),
@fileNamePath VARCHAR(200),
@fileName VARCHAR(200),
@sql NVARCHAR(1000)
if(MONTH(GETDATE()) != '12')--計劃每月執行,如果是12月則可以更新分局
begin
--生成新的文件組
SET @fileGroupName='IN_'+ convert(varchar(4),(YEAR(GETDATE())+1))
PRINT @fileGroupName
SET @sql='ALTER DATABASE [iom_db] ADD FILEGROUP '+@fileGroupName
PRINT @sql
EXEC(@sql)
--新建文件
SET @fileNamePath='C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA'
+ @fileGroupName +'.NDF'
SET @fileName=N'File'+convert(varchar(4),(YEAR(GETDATE())+1))
SET @sql='ALTER DATABASE [iom_db] ADD FILE (NAME='''+@fileName+''',FILENAME=N'''+@fileNamePath+''') TO FILEGROUP'+' '+@fileGroupName
PRINT @sql
PRINT 1
EXEC(@sql)
PRINT 2
--修改分區方案,用一個新的文件組用於存放下一新增的數據
SET @sql='ALTER PARTITION SCHEME [RangeSchema_CreateTime] NEXT USED'+' '+@fileGroupName
EXEC(@sql)
PRINT 3
ALTER PARTITION FUNCTION RangeTime() --分區函數
SPLIT RANGE (convert(datetime, convert(varchar(4),(YEAR(GETDATE())+1))+'-12-31 00:00:00.000'))
end
oracle:
首先明確分區表和表分區的區別:表分區是一種思想,分區表示一種技術實現。當表的大小過G的時候可以考慮進行表分區,提高查詢效率,均衡IO。oracle分區表是oracle數據庫提供的一種表分區的實現形式。表進行分區後,邏輯上仍然是一張表,原來的查詢SQL同樣生效,同時可以採用使用分區查詢來優化SQL查詢效率,不至於每次都掃描整個表
一、分區表基本操作
1、按時間分區表創建:
create table t_test (
pk_id number(30) not null,
add_date_time DATE,
constraintPK_T_TEST primary key (pk_id)
)
PARTITION BY RANGE (add_date_time)
(
PARTITIONt_test_2013_less VALUES LESS THAN (TO_DATE('2013-01-01 00:00:00','yyyy-mm-ddhh24:mi:ss')) TABLESPACE TS_MISPS,
PARTITIONt_test_2013 VALUES LESS THAN (TO_DATE('2014-01-01 00:00:00','yyyy-mm-ddhh24:mi:ss')) TABLESPACE TS_MISPS,
PARTITION t_test_2014VALUES LESS THAN (TO_DATE('2015-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss'))TABLESPACE TS_MISPS
)
其中add_date_time爲分區字段,每一年一個分區。
插入100W數據
declare
i int := 1;
yearVARCHAR2(20);
begin
loop
year := CASEmod(i, 3)
WHEN 0 THEN
'2012-01-14 12:00:00'
WHEN 1 THEN
'2013-01-14 12:00:00'
ELSE
'2014-01-14 12:00:00'
END;
insert into t_test values(i, to_date(year, 'yyyy-mm-dd hh24:mi:ss'));
exit when i= 1000000;
i := i + 1;
end loop;
end;
查看分區表的分區的詳細信息
Select table_name,partition_name,high_value fromdba_tab_partitions where table_name='T_TEST';
2、分區表修改
2.1增加一個分區
分兩種情況:1.沒有maxvalue分區。2.有maxvalue分區。我們創建的分區就是沒有maxValue的分區
1.沒有maxvalue分區添加新分區:
alter table t_test add partition t_test_2015 VALUESLESS THAN (TO_DATE('2015-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss')) TABLESPACETS_MISPS ;
2、有maxvalue分區添加新分區:
有了maxvalue,就不能直接add partition,而是需要max分區split。例如我們將創建的分區的語句修改下:
create table t_test (
pk_id number(30) not null,
add_date_time DATE,
constraintPK_T_TEST primary key (pk_id)
)
PARTITION BY RANGE (add_date_time)
(
PARTITIONt_test_2013_less VALUES LESS THAN (TO_DATE('2013-01-01 00:00:00','yyyy-mm-ddhh24:mi:ss')) TABLESPACE TS_MISPS,
PARTITIONt_test_2013 VALUES LESS THAN (TO_DATE('2014-01-01 00:00:00','yyyy-mm-ddhh24:mi:ss')) TABLESPACE TS_MISPS,
PARTITIONt_test_2014 VALUES LESS THAN (TO_DATE('2015-01-01 00:00:00','yyyy-mm-ddhh24:mi:ss')) TABLESPACE TS_MISPS,
PARTITION t_test_maxVALUES LESS THAN (MAXVALUE)
)
增加一個2016年的分區語句爲:
alter table t_test split partition t_test_max at(TO_DATE('2016-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss')) into (partitiont_test_2015,partition t_test_max);
2.2刪除一個分區
alter table t_test drop partition t_test_2014
注:droppartition時,該分區內存儲的數據也將同時刪除,你的本意是希望刪除掉指定的分區但保留數據,你應該使用merge partition,執行該語句會導致glocal索引的失效需要重建全局索引
2.3合併分區
相鄰的分區可以merge爲一個分區,新分區的下邊界爲原來邊界值較低的分區,上邊界爲原來邊界值較高的分區,原先的局部索引相應也會合並,全局索引會失效,需要rebuild。
Alter table t_test merge partitions t_test_2013 ,t_Test_2014 into partition t_Test_2013_to_2014
二、對分區表進行查詢
2.1查詢
不使用分區查詢:默認查詢所有分區數據
select * from t_test
使用分區查詢:只查詢該分區數據
select * from t_testpartition(t_test_2014) where add_date_time >=TO_DATE('2014-01-01 00:00:00','yyyy-mm-dd hh24:mi:ss');
2.1插入
insert into t_test values(i, to_date(year,'yyyy-mm-dd hh24:mi:ss'));
2.1刪除
使用分區刪除
更新的時候指定了分區,而根據查詢的記錄不在該分區中時,將不會刪除數據
delete t_test partition(t_test_2013) where id=1;
不使用分區刪除
delete t_test whereid=1;
2.1修改
使用分區更新
更新的時候指定了分區,而根據查詢的記錄不在該分區中時,將不會更新數據
delete t_test where id=1;
update t_test partition(t_test) set id=1 where id=2;
不使用分區
delete t_test where id=1;
update t_test set id=1 where id=2;
三、普通表和分區表互轉
普通表—>分區表
1、新建一個字段一樣的中間的分區表(T_NEW)
2、將T數據導入到T_NEW中
INSERT INTO T SELECT field1,filed2, …from T
將老表重命名
RENAME T TO T_OLD;
將新表重命名
RENAME T_NEW TO T;
這種適合靜態操作,不保證數據一致性。如果在生產環境切換,利用利用在線重定義功能
mysql:
CREATE TABLE p1
-> ( a INT,
-> b INT,
-> c INT )
-> PARTITION BY RANGE COLUMNS (a)
-> ( PARTITION p01 VALUES LESS THAN (10),
-> PARTITION p02 VALUES LESS THAN (20),
-> PARTITION p03 VALUES LESS THAN (30),
-> PARTITION p04 VALUES LESS THAN (MAXVALUE) );
---------------------
Mysql的安裝方法可以參考:
http://blog.csdn.net/jhq0113/article/details/43812895
Mysql分區表的介紹可以參考:
http://blog.csdn.net/jhq0113/article/details/44592865
1.檢查你的Mysql是否支持分區
mysql> SHOW VARIABLES LIKE '%partition%';
若結果如下,表示你的Mysql支持表分區:
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| have_partition_engine | YES |
+-----------------------+-------+
1 row in set (0.00 sec)
RANGE分區表創建方式:
DROP TABLE IF EXISTS `my_orders`;
CREATE TABLE `my_orders` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '表主鍵',
`pid` int(10) unsigned NOT NULL COMMENT '產品ID',
`price` decimal(15,2) NOT NULL COMMENT '單價',
`num` int(11) NOT NULL COMMENT '購買數量',
`uid` int(10) unsigned NOT NULL COMMENT '客戶ID',
`atime` datetime NOT NULL COMMENT '下單時間',
`utime` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '修改時間',
`isdel` tinyint(4) NOT NULL DEFAULT '0' COMMENT '軟刪除標識',
PRIMARY KEY (`id`,`atime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*********分區信息**************/
PARTITION BY RANGE (YEAR(atime))
(
PARTITION p0 VALUES LESS THAN (2016),
PARTITION p1 VALUES LESS THAN (2017),
PARTITION p2 VALUES LESS THAN MAXVALUE
);
以上是一個簡單的訂單表,分區字段是atime,根據RANGE分區,這樣當你向該表中插入數據的時候,Mysql會根據YEAR(atime)的值進行分區存儲。
檢查分區是否創建成功,執行查詢語句:
EXPLAIN PARTITIONS SELECT * FROM `my_orders`
若成功,結果如下:
性能分析:
1).創建同樣表結構,但沒有進行分區的表
DROP TABLE IF EXISTS `my_order`;
CREATE TABLE `my_order` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '表主鍵',
`pid` int(10) unsigned NOT NULL COMMENT '產品ID',
`price` decimal(15,2) NOT NULL COMMENT '單價',
`num` int(11) NOT NULL COMMENT '購買數量',
`uid` int(10) unsigned NOT NULL COMMENT '客戶ID',
`atime` datetime NOT NULL COMMENT '下單時間',
`utime` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '修改時間',
`isdel` tinyint(4) NOT NULL DEFAULT '0' COMMENT '軟刪除標識',
PRIMARY KEY (`id`,`atime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2).向兩張表中插入相同的數據
/**************************向分區表插入數據****************************/
INSERT INTO my_orders(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89757,CURRENT_TIMESTAMP());
INSERT INTO my_orders(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89757,'2016-05-01 00:00:00');
INSERT INTO my_orders(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89757,'2017-05-01 00:00:00');
INSERT INTO my_orders(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89757,'2018-05-01 00:00:00');
INSERT INTO my_orders(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89756,'2015-05-01 00:00:00');
INSERT INTO my_orders(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89756,'2016-05-01 00:00:00');
INSERT INTO my_orders(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89756,'2017-05-01 00:00:00');
INSERT INTO my_orders(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89756,'2018-05-01 00:00:00');
/**************************向未分區表插入數據****************************/
INSERT INTO my_order(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89757,CURRENT_TIMESTAMP());
INSERT INTO my_order(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89757,'2016-05-01 00:00:00');
INSERT INTO my_order(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89757,'2017-05-01 00:00:00');
INSERT INTO my_order(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89757,'2018-05-01 00:00:00');
INSERT INTO my_order(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89756,'2015-05-01 00:00:00');
INSERT INTO my_order(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89756,'2016-05-01 00:00:00');
INSERT INTO my_order(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89756,'2017-05-01 00:00:00');
INSERT INTO my_order(`pid`,`price`,`num`,`uid`,`atime`) VALUES(1,12.23,1,89756,'2018-05-01 00:00:00');
3).主從複製,大約20萬條左右(主從複製的數據和真實環境有差距,但是能體現出表分區查詢的性能優劣)
/**********************************主從複製大量數據******************************/
INSERT INTO `my_orders`(`pid`,`price`,`num`,`uid`,`atime`) SELECT `pid`,`price`,`num`,`uid`,`atime` FROM `my_orders`;
INSERT INTO `my_order`(`pid`,`price`,`num`,`uid`,`atime`) SELECT `pid`,`price`,`num`,`uid`,`atime` FROM `my_order`;
4).查詢測試
/***************************查詢性能分析**************************************/
SELECT * FROM `my_orders` WHERE `uid`=89757 AND `atime`< CURRENT_TIMESTAMP();
/****用時0.084s****/
SELECT * FROM `my_order` WHERE `uid`=89757 AND `atime`< CURRENT_TIMESTAMP();
/****用時0.284s****/
通過以上查詢可以明顯看出進行表分區的查詢性能更好,查詢所花費的時間更短。
分析查詢過程:
EXPLAIN PARTITIONS SELECT * FROM `my_orders` WHERE `uid`=89757 AND `atime`< CURRENT_TIMESTAMP();
EXPLAIN PARTITIONS SELECT * FROM `my_order` WHERE `uid`=89757 AND `atime`< CURRENT_TIMESTAMP();
通過以上結果可以看出,my_orders表查詢直接經過p0分區,只掃描了49386行,而my_order表沒有進行分區,掃描了196983行,這也是性能得到提升的關鍵所在。
當然,表的分區並不是分的越多越好,當表的分區太多時找分區又是一個性能的瓶頸了,建議在200個分區以內。
LIST分區表創建方式:
/*****************創建分區表*********************/
CREATE TABLE `products` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '表主鍵' ,
`name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '產品名稱' ,
`metrial` tinyint UNSIGNED NOT NULL COMMENT '材質' ,
`weight` double UNSIGNED NOT NULL DEFAULT 0 COMMENT '重量' ,
`vol` double UNSIGNED NOT NULL DEFAULT 0 COMMENT '容積' ,
`c_id` tinyint UNSIGNED NOT NULL COMMENT '供貨公司ID' ,
PRIMARY KEY (`id`,`c_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8
/*********分區信息**************/
PARTITION BY LIST(c_id)
(
PARTITION pA VALUES IN (1,3,11,13),
PARTITION pB VALUES IN (2,4,12,14),
PARTITION pC VALUES IN (5,7,15,17),
PARTITION pD VALUES IN (6,8,16,18),
PARTITION pE VALUES IN (9,10,19,20)
);
可以看出,LIST分區和RANGE分區很類似,這裏就不做性能分析了,和RANGE很類似。
HASH分區表的創建方式:
/*****************分區表*****************/
CREATE TABLE `msgs` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '表主鍵',
`sender` int(10) unsigned NOT NULL COMMENT '發送者ID',
`reciver` int(10) unsigned NOT NULL COMMENT '接收者ID',
`msg_type` tinyint(3) unsigned NOT NULL COMMENT '消息類型',
`msg` varchar(225) NOT NULL COMMENT '消息內容',
`atime` int(10) unsigned NOT NULL COMMENT '發送時間',
`sub_id` tinyint(3) unsigned NOT NULL COMMENT '部門ID',
PRIMARY KEY (`id`,`sub_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*********分區信息**************/
PARTITION BY HASH(sub_id)
PARTITIONS 10;
以上語句代表,msgs表按照sub_id進行HASH分區,一共分了十個區。
Key分區和HASH分區很類似,不再介紹,若想了解可以參考Mysql官方文檔進行詳細瞭解。
子分區的創建方式:
CREATE TABLE `msgss` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '表主鍵',
`sender` int(10) unsigned NOT NULL COMMENT '發送者ID',
`reciver` int(10) unsigned NOT NULL COMMENT '接收者ID',
`msg_type` tinyint(3) unsigned NOT NULL COMMENT '消息類型',
`msg` varchar(225) NOT NULL COMMENT '消息內容',
`atime` int(10) unsigned NOT NULL COMMENT '發送時間',
`sub_id` tinyint(3) unsigned NOT NULL COMMENT '部門ID',
PRIMARY KEY (`id`,`atime`,`sub_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*********分區信息**************/
PARTITION BY RANGE (atime) SUBPARTITION BY HASH (sub_id)
(
PARTITION t0 VALUES LESS THAN(1451577600)
(
SUBPARTITION s0,
SUBPARTITION s1,
SUBPARTITION s2,
SUBPARTITION s3,
SUBPARTITION s4,
SUBPARTITION s5
),
PARTITION t1 VALUES LESS THAN(1483200000)
(
SUBPARTITION s6,
SUBPARTITION s7,
SUBPARTITION s8,
SUBPARTITION s9,
SUBPARTITION s10,
SUBPARTITION s11
),
PARTITION t2 VALUES LESS THAN MAXVALUE
(
SUBPARTITION s12,
SUBPARTITION s13,
SUBPARTITION s14,
SUBPARTITION s15,
SUBPARTITION s16,
SUBPARTITION s17
)
);
檢查子分區是否創建成功:
EXPLAIN PARTITIONS SELECT * FROM msgss;