在大型的企业应用或企业级的数据库应用中 要处理的数据量通常可以达到几十到几百GB 有的甚至可以到TB级 虽然存储介质和数据处理技术的发展也很快 但是仍然不能满足用户的需求 为了使用户的大量的数据在读写 *** 作和查询中速度更快 Oracle提供了对表和索引进行分区的技术 以改善大型应用系统的性能
使用分区的优点
·增强可用性 如果表的某个分区出现故障 表在其他分区的数据仍然可用
·维护方便 如果表的某个分区出现故障 需要修复数据 只修复该分区即可
·均衡I/O 可以把不同的分区映射到磁盘以平衡I/O 改善整个系统性能
·改善查询性能 对分区对象的查询可以仅搜索自己关心的分区 提高检索速度
Oracle数据库提供对表或索引的分区方法有三种
·范围分区
·Hash分区(散列分区)
·复合分区
下面将以实例的方式分别对这三种分区方法来说明分区表的使用 为了测试方便 我们先建三个表空间
以下为引用的内容
create tablespace dinya_space
datafile /test/demo/oracle/demodata/dinya dnf size M
create tablespace dinya_space
datafile /test/demo/oracle/demodata/dinya dnf size M
create tablespace dinya_space
datafile /test/demo/oracle/demodata/dinya dnf size M
分区表的创建
范围分区
范围分区就是对数据表中的某个值的范围进行分区 根据某个值的范围 决定将该数据存储在哪个分区上 如根据序号分区 根据业务记录的创建日期进行分区等
需求描述 有一个物料交易表 表名 material_transactions 该表将来可能有千万级的数据记录数 要求在建该表的时候使用分区表 这时候我们可以使用序号分区三个区 每个区中预计存储三千万的数据 也可以使用日期分区 如每五年的数据存储在一个分区上
根据交易记录的序号分区建表 以下为引用的内容
SQL>create table dinya_test
(
transaction_id number primary key
item_id number( ) not null
item_description varchar ( )
transaction_date date not null
)
partition by range (transaction_id)
(
partition part_ values less than( ) tablespace dinya_space
partition part_ values less than( ) tablespace dinya_space
partition part_ values less than(maxvalue) tablespace dinya_space
)
Table created
建表成功 根据交易的序号 交易ID在三千万以下的记录将存储在第一个表空间dinya_space 中 分区名为:par_ 在三千万到六千万之间的记录存储在第二个表空间
dinya_space 中 分区名为 par_ 而交易ID在六千万以上的记录存储在第三个表空间dinya_space 中 分区名为par_
根据交易日期分区建表
以下为引用的内容
SQL>create table dinya_test
(
transaction_id number primary key
item_id number( ) not null
item_description varchar ( )
transaction_date date not null
)
partition by range (transaction_date)
(
partition part_ values less than(to_date( yyyy mm dd ))
tablespace dinya_space
partition part_ values less than(to_date( yyyy mm dd ))
tablespace dinya_space
partition part_ values less than(maxvalue) tablespace dinya_space
)
Table created
这样我们就分别建了以交易序号和交易日期来分区的分区表 每次插入数据的时候 系统将根据指定的字段的值来自动将记录存储到制定的分区(表空间)中
当然 我们还可以根据需求 使用两个字段的范围分布来分区 如partition
by range ( transaction_id transaction_date)
分区条件中的值也做相应的改变 请读者自行测试
Hash分区(散列分区)
散列分区为通过指定分区编号来均匀分布数据的一种分区类型 因为通过在I/O设备上进行散列分区 使得这些分区大小一致 如将物料交易表的数据根据交易ID散列地存放在指定的三个表空间中
以下为引用的内容
SQL>create table dinya_test
(
transaction_id number primary key
item_id number( ) not null
item_description varchar ( )
transaction_date date
)
partition by hash(transaction_id)
(
partition part_ tablespace dinya_space
partition part_ tablespace dinya_space
partition part_ tablespace dinya_space
)
Table created
建表成功 此时插入数据 系统将按transaction_id将记录散列地插入三个分区中 这里也就是三个不同的表空间中
复合分区
有时候我们需要根据范围分区后 每个分区内的数据再散列地分布在几个表空间中 这样我们就要使用复合分区 复合分区是先使用范围分区 然后在每个分区内再使用散列分区的一种分区方法 如将物料交易的记录按时间分区 然后每个分区中的数据分三个子分区 将数据散列地存储在三个指定的表空间中
以下为引用的内容
SQL>create table dinya_test
(
transaction_id number primary key
item_id number( ) not null
item_description varchar ( )
transaction_date date
)
partition by range(transaction_date)subpartition by hash(transaction_id)
subpartitions store in (dinya_space dinya_space dinya_space )
(
partition part_ values less than(to_date( yyyy mm dd ))
partition part_ values less than(to_date( yyyy mm dd ))
partition part_ values less than(maxvalue)
)
Table created
该例中 先是根据交易日期进行范围分区 然后根据交易的ID将记录散列地存储在三个表空间中
分区表 *** 作
以上了解了三种分区表的建表方法 下面将使用实际的数据并针对按日期的范围分区来测试分区表的数据记录的 *** 作
插入记录
以下为引用的内容
SQL>insert into dinya_test values( BOOKS sysdate)
row created
SQL>insert into dinya_test values( BOOKS sysdate+ )
row created
SQL>insert into dinya_test values( BOOKS to_date( yyyy mm dd ))
row created
SQL>insert into dinya_test values( BOOKS to_date( yyyy mm dd ))
row created
SQL>insert into dinya_test values( BOOKS to_date( yyyy mm dd ))
row created
SQL>insert into dinya_test values( BOOKS to_date( yyyy mm dd ))
row created
SQL>mit
Commit plete
SQL>
按上面的建表结果 年前的数据将存储在第一个分区part_ 上 而 年到 年的交易数据将存储在第二个分区part_ 上 年以后的记录存储在第三个分区part_ 上
查询分区表记录 以下为引用的内容
SQL>select * from dinya_test partition(part_ )
TRANSACTION_ID ITEM_ID ITEM_DESCRIPTION TRANSACTION_DATE
BOOKS : :
BOOKS : :
SQL>
SQL>select * from dinya_test partition(part_ )
TRANSACTION_ID ITEM_ID ITEM_DESCRIPTION TRANSACTION_DATE
BOOKS
BOOKS
SQL>
SQL>select * from dinya_test partition(part_ )
TRANSACTION_ID ITEM_ID ITEM_DESCRIPTION TRANSACTION_DATE
BOOKS
BOOKS
SQL>
从查询的结果可以看出 插入的数据已经根据交易时间范围存储在不同的分区中 这里是指定了分区的查询 当然也可以不指定分区 直接执行select * from dinya_test查询全部记录
在也检索的数据量很大的时候 指定分区会大大提高检索速度
更新分区表的记录
以下为引用的内容
SQL>update dinya_test partition(part_ ) t set em_description= DESK where
t transaction_id=
row updated
SQL>mit
Commit plete
SQL>
这里将第一个分区中的交易ID= 的记录中的item_description字段更新为 DESK 可以看到已经成功更新了一条记录 但是当更新的时候指定了分区 而根据查询的记录不在该分区中时 将不会更新数据 请看下面的例子 以下为引用的内容
SQL>update dinya_test partition(part_ ) t set em_description= DESK where
t transaction_id=
rows updated
SQL>mit
Commit plete
SQL>
指定了在第一个分区中更新记录 但是条件中限制交易ID为 而查询全表 交易ID为 的记录在第三个分区中 这样该条语句将不会更新记录
删除分区表记录
以下为引用的内容
SQL>delete from dinya_test partition(part_ ) t where t transaction_id=
row deleted
SQL>mit
Commit plete
SQL>
上面例子删除了第二个分区part_ 中的交易记录ID为 的一条记录 和更新数据相同 如果指定了分区 而条件中的数据又不在该分区中时 将不会删除任何数据
分区表索引的使用
分区表和一般表一样可以建立索引 分区表可以创建局部索引和全局索引 当分区中出现许多事务并且要保证所有分区中的数据记录的唯一性时采用全局索引
局部索引分区的建立
以下为引用的内容
SQL>create index dinya_idx_t on dinya_test(item_id)
local
(
partition idx_ tablespace dinya_space
partition idx_ tablespace dinya_space
partition idx_ tablespace dinya_space
)
Index created
SQL>
看查询的执行计划 从下面的执行计划可以看出 系统已经使用了索引
以下为引用的内容
SQL>select * from dinya_test partition(part_ ) t where em_id=
Execution Plan
SELECT STATEMENT Optimizer=CHOOSE (Cost= Card= Bytes= )
TABLE ACCESS (BY LOCAL INDEX ROWID) OF DINYA_TEST (Cost=
Card= Bytes= )
INDEX (RANGE SCAN) OF DINYA_IDX_T (NON UNIQUE) (Cost=
Card= )
Statistics
recursive calls
db block gets
consistent gets
physical reads
redo size
bytes sent via SQL*Net to client
bytes received via SQL*Net from client
SQL*Net roundtrips to/from client
sorts (memory)
sorts (disk)
rows processed
SQL>
全局索引分区的建立
全局索引建立时global 子句允许指定索引的范围值 这个范围值为索引字段的范围值
以下为引用的内容
SQL>create index dinya_idx_t on dinya_test(item_id)
global partition by range(item_id)
(
partition idx_ values less than ( ) tablespace dinya_space
partition idx_ values less than ( ) tablespace dinya_space
partition idx_ values less than (maxvalue) tablespace dinya_space
)
Index created
SQL>
本例中对表的item_id字段建立索引分区 当然也可以不指定索引分区名直接对整个表建立索引 如
以下为引用的内容
SQL>create index dinya_idx_t on dinya_test(item_id)
Index created
SQL>
同样的 对全局索引根据执行计划可以看出索引已经可以使用
以下为引用的内容
SQL>select * from dinya_test t where em_id=
Execution Plan
SELECT STATEMENT Optimizer=CHOOSE (Cost= Card= Bytes= )
TABLE ACCESS (BY GLOBAL INDEX ROWID) OF DINYA_TEST (Cost
= Card= Bytes= )
INDEX (RANGE SCAN) OF DINYA_IDX_T (NON UNIQUE) (Cost=
Card= )
Statistics
recursive calls
db block gets
consistent gets
physical reads
redo size
bytes sent via SQL*Net to client
bytes received via SQL*Net from client
SQL*Net roundtrips to/from client
sorts (memory)
sorts (disk)
rows processed
SQL>
分区表的维护
了解了分区表的建立 索引的建立 表和索引的使用后 在应用的还要经常对分区进行维护和管理 日常维护和管理的内容包括 增加一个分区 合并一个分区及删除分区等等 下面以范围分区为例说明增加 合并 删除分区的一般 *** 作
增加一个分区:
以下为引用的内容
SQL>alter table dinya_test
add partition part_ values less than(to_date( yyyy mm dd ))
tablespace dinya_spa
ce
Table altered
SQL>
增加一个分区的时候 增加的分区的条件必须大于现有分区的最大值 否则系统将提示ORA partition bound must collate higher than that of the last partition 错误
合并一个分区
以下为引用的内容
SQL>alter table dinya_test merge partitions part_ part_ into partition part_
Table altered
SQL>
在本例中将原有的表的part_ 分区和part_ 分区进行了合并 合并后的分区为part_ 如果在合并的时候把合并后的分区定为part_ 的时候 系统将提示ORA cannot reuse lower bound partition as resulting partition 错误
删除分区
以下为引用的内容
SQL>alter table dinya_test drop partition part_
Table altered
SQL>
删除分区表的一个分区后 查询该表的数据时显示 该分区中的数据已全部丢失 所以执行删除分区动作时要慎重 确保先备份数据后再执行 或将分区合并
总结
lishixinzhi/Article/program/Oracle/201311/17329
分区介绍:
一、什么是分区?
所谓分区,就是将一个表分成多个区块进行 *** 作和保存,从而降低每次 *** 作的数据,提高性能。而对于应用来说则是透明的,从逻辑上看只有一张表,但在物理上这个表可能是由多个物理分区组成的,每个分区都是独立的对象,可以进行独立处理。
二、分区作用
1.可以逻辑数据分割,分割数据能够有多个不同的物理文件路径。
2.可以存储更多的数据,突破系统单个文件最大限制。
3.提升性能,提高每个分区的读写速度,提高分区范围查询的速度。
4.可以通过删除相关分区来快速删除数据
5.通过跨多个磁盘来分散数据查询,从而提高磁盘I/O的性能。
6.涉及到例如SUM()、COUNT()这样聚合函数的查询,可以很容易的进行并行处理。
7.可以备份和恢复独立的分区,这对大数据量很有好处。
三、分区能支持的引擎
MySQL支持大部分引擎创建分区,入MyISAM、InnoDB等;不支持MERGE和CSV等来创建分区。同一个分区表中的所有分区必须是同一个存储引擎。值得注意的是,在MySQL8版本中,MyISAM表引擎不支持分区。
四、确认MySQL支持分区
从MySQL5.1开始引入分区功能,可以如下方式查看是否支持:
老版本用:SHOW VARIABLES LIKE '%partition%'
新版本用:show plugins
五、分区类型
1. RANGE分区:基于属于一个给定连续区间的列值,把多行分配给分区。
例如,可以将一个表通过年份划分成两个分区,2001 -2010年、2011-2020。
2. LIST分区:类似于RANGE分区,LIST是列值匹配一个离散值集合中的某个值来进行选择。
比如 根据字段 把值为1、3、5的放到一起,2、4、6的另外放到一起 等等...
3. HASH分区:基于用户定义的表达式的返回值来进行选择分区,该表达式使用将要插入到表中的这些行的列值来进行计算,这个函数必须产生非负整数值。
通过HASH运算来进行分区,分布的比较均匀
4. KEY分区:类似于按HASH分区,由MySQL服务器提供其自身的哈希函数。
按照KEY进行分区类似于按照HASH分区
六、使用分区注意事项
1. 如果表中存在primary key 或者 unique key 时,分区的列必须是paimary key或者unique key的一个组成部分,也就是说,分区函数的列只能从pk或者uk这些key中取子集
2. 如果表中不存在任何的paimary key或者unique key,则可以指定任何一个列作为分区列
3. 5.5版本前的RANGE、LIST、HASH分区要求分区键必须是int;MySQL5.5及以上,支持非整形的RANGE和LIST分区,即:range columns 和 list columns (可以用字符串来进行分区)。
七、分区命名
1. 分区的名字基本上遵循其他MySQL 标识符应当遵循的原则,例如用于表和数据库名字的标识符。应当注意的是,分区的名字是不区分大小写的。
2. 无论使用何种类型的分区,分区总是在创建时就自动的顺序编号,且从0开始记录。
八、 创建分区
1. RANGE分区:
解读:以上为 uuid小于5时放到p0分区下,uuid大于5且小于10放到p1分区下,uuid大于10且小于15放到p2分区下,uuid大于15 一直到最大值的存在p3分区下
2. LIST分区:
解读:以上为uuid 等于1/2/3/5时放到p0分区,7/9/10放到p1分区,11/15放到p2分区。当时用insert into时 如果uuid的值不存在p0/p1/p2分区时,则会插入失败而报错。
3. HASH分区:
HASH分区主要用来确保数据在预先确定数目的分区中平均分布。在RANGE分区和LIST分区中必须明确指定一个指定的列值或列值集合以指定应该保存在哪个分区中。而在HASH分区中,MySQL会自动完成这些工作,要做的只是基于将要被哈希的列值指定一个表达式,以及指定被分区的表将要被分割成的分区数量,如:
解读:MySQL自动创建3个分区,在执行insert into时,根据插入的uuid通过算法来自动分配区间。
注意:
(1) 由于每次插入、更新、删除一行,这个表达式都要计算一次,这意味着非常复杂的表达式可能会引起性能问题,尤其是在执行同时影响大量行的运算(例如批量插入)的时候。
(2) 最有效率的哈希函数是只对单个表列进行计算,并且它的值随列值进行一致的增大或减小,因为这考虑了在分区范围上的“修剪”。也就是说,表达式值和它所基于的列的值变化越接近,就越能有效地使用该表达式来进行HASH分区。
3.1:线性HASH分区
线性HASH分区在“PARTITION BY”子句中添加“LINEAR”关键字。
线性HASH分区的有点在于增加、删除、合并和拆分分区将变得更加快捷,有利于处理含有及其大量数据的表。它的缺点在于各个分区间数据的分布不大可能均衡。
4. KEY分区
类似于HASH分区,HASH分区允许用户自定义的表达式,而KEY分区则不允许使用用户自定义的表达式;HASH分区只支持整数分区,KEY分区支持除了blob和text类型之外的其他数据类型分区。
与HASH分区不同,创建KEY分区表的时候,可以不指定分区键,默认会选择使用主键或唯一键作为分区键,没有主键或唯一键,就必须指定分区键。
解读:根据分区键来进行分区
5. 子分区
子分区是分区表中,每个分区的再次分割,适合保存非常大量的数据。
解读:主分区使用RANGE按照年来进行分区,有3个RANGE分区。这3个分区中又被进一步分成了2个子分区,实际上,整个表被分成了3 * 2 = 6个分区。每个子分区按照天进行HASH分区。小于2017的放在一起,2017-2020的放在一起,大于2020的放在一起。
注意:
(1) 在MySQL5.1中,对于已经通过RANGE或LIST分区了的表在进行子分区是可能的。子分区既可以使用HASH分区,也可以使用KEY分区。这也被称为复合分区。
(2) 每个分区必须有相同数量的子分区。
(3) 如果在一个分区表上的任何分区上使用SUBPARTITION来明确定义任何子分区,那么就必须定义所有的子分区。
(4) 每个SUBPARTITION子句必须包含(至少)子分区的一个名字。
(5) 在每个子分区内,子分区的名字必须是惟一的,目前在整个表中,也要保持唯一。例如:
子分区可以用于特别大的表,可以在多个磁盘间分配数据和索引。例如:
九、MySQL分区处理NULL值的方式
十、分区管理概述
可以对分区进行添加、删除、重新定义、合并或拆分等管理 *** 作。
① RANGE和LIST分区的管理
1. 删除分区语句如:alter table tbl_test drop partition p0
注意:
(1) 当删除了一个分区,也同时删除了该分区中所有的数据。
(2) 可以通过show create table tbl_test来查看新的创建表的语句。
(3) 如果是LIST分区的话,删除的数据不能新增进来,因为这些行的列值包含在已经删除了的分区的值列表中。
2. 添加分区语句如:alter table tbl_test add partition(partition p3 values less than(50))
注意:
(1) 对于RANGE分区的表,只可以添加新的分区到分区列表的最高端。
(2) 对于LIST分区的表,不能添加已经包含在现有分区值列表中的任意值。
3. 如果希望能不丢失数据的条件下重新定义分区,可以使用如下语句:
REORGANIZE会对分区的数据进行重构。
ALTER TABLE tbl_name REORGANIZE PARTITION partition_list INTO(partition_definitions)
(1) 拆分分区如:
ALTER TABLE tbl_name REORGANIZE PARTITION partition_list INTO(partition s0 values less than(5),partition s1 values less than(10))
或者如:
ALTER TABLE tbl_name REORGANIZE PARTITION p0 INTO(partition s0 values in(1,2,3), partition s1 values in(4,5))
(2) 合并分区如:ALTER TABLE tbl_name REORGANIZE PARTITION s0,s1 INTO(partition p0 values in(1,2,3,4,5))
4. 删除所有分区,但保留数据,形式:ALTER TABLE tbl_name remove partitioning
② HASH和KEY分区的管理
1. 减少分区数量语句如:ALTER TABLE tbl_name COALESCE PARTITION 2
2. 添加分区数量语句如:ALTER TABLE tbl_name add PARTITION partitions 2
③ 其他分区管理语句
1. 重建分区:类似于先删除保存在分区中的所有记录,然后重新插入它们,可用于整理分区碎片。如:ALTER table tbl_name REBUILD PARTITION p2,p3
2. 优化分区:如果从分区中删除了大量的行,或者对一个带有可变长度的行(也就是说,有VARCHAR,BLOB或TEXT类型的列)做了许多修改,可以使用 ALTER TABLE tbl_name OPTIMIZE PARTITION来收回没有使用的空间,并整理分区数据文件的碎片。如:ALTER TABLE tbl_name OPTIMIZE PARTITION p2,p3
3. 分析分区:读取并保存分区的键分布,如:ALTER TABLE tbl_name ANALYZE PARTITION p2,p3
4. 检查分区:检查分区中的数据或索引是否已经被破坏,如:ALTER TABLE tbl_name CHECK PARTITION p2,p3
5. 修补分区:修补被破坏的分区,如:ALTER TABLE tbl_name REPAIR PARTITION p2,p3
十、查看分区信息
1. 查看分区信息:select * from information_schema.partitions where table_schema='arch1' and table_name = 'tbl_test' G
2. 查看分区上的数据:select * from tbl_test partition(p0)
3. 查看MySQL会 *** 作的分区:explain partitions select * from tbl_test where uuid = 2
十一、 局限性
1. 最大分区数目不能超过1024,一般建议对单表的分区数不要超过50个。
2. 如果含有唯一索引或者主键,则分区列必须包含在所有的唯一索引或者主键在内。
3. 不支持外键。
4. 不支持全文索引,对分区表的分区键创建索引,那么这个索引也将被分区。
5. 按日期进行分区很合适,因为很多日期函数可以用。但是对字符串来说合适的分区函数不太多。
6. 只有RANGE和LIST分区能进行子分区,HASH和KEY分区不能进行子分区。
7. 临时表不能被分区。
8. 分区表对于单条记录的查询没有优势。
9. 要注意选择分区的成本,没插入一行数据都需要按照表达式筛选插入的分区。
10. 分区字段尽量不要可以为null
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)