对已存在的表进行分区时遇到的坑

在网上能够找到很多关于表分区的资料,可是大部分都是在介绍如何给一个新表创建表分区,而对已存在的表如何做分区的文章相对比较少,因此一些坑没有被“挖掘”出来或者“曝光率”比较低。

笔者最近遇到了一个这样的案例,刚好踩到了两个坑,现分享给大家。

对已存在的表进行分区最常见的方法就是重建聚集索引或者创建聚集索引(如果表上没有)。因为聚集索引的页级就是实际数据,而重建或者创建聚集索引时会重新组织页,所以如果在重建或者创建索引时指定分区架构,那么该表上所有的数据就会按照分区架构进行表分区。

在使用此法对表进行分区,有两个坑请大家注意:

坑一:重建索引时,提示“新的索引定义与现有的索引强制的约束不匹配”

请看如下代码:

CREATE clustered index

PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID ON Sales.SalesOrderDetail(SalesOrderID, SalesOrderDetailID) WITH DROP_EXISTING

ON [PS_Sod](ModifiedDate)

参数with drop_existing表示在线重建索引;

PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID是索引的名称,它建立在表Sales.SalesOrderDetail的SalesOrderID, SalesOrderDetailID字段上;

PS_Sod为分区架构,其参数ModifiedDate表示分区列;

当我执行时,提示错误如下:

消息1907,级别16,状态1,第2 行

无法重新重建索引‘PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID‘。新的新的索引定义与现有的索引强制的约束不匹配.

从报错信息来看,新创建的索引与原索引的约束不匹配,于是执行如下语句,查看当前表身上的约束信息:

SELECT CONSTRAINT_TYPE FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS

WHERE CONSTRAINT_NAME = ‘PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID‘

返回的结果为:primary

也就是说,当前表上的(SalesOrderID, SalesOrderDetailID)存在主键约束,从而确保(SalesOrderID, SalesOrderDetailID)的唯一性,而重建索引时,没有指定唯一性,因此需要改成如下语句:

CREATE UNIQUE clustered index

PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID ON Sales.SalesOrderDetail(SalesOrderID, SalesOrderDetailID) WITH DROP_EXISTING

ON [PS_Sod](ModifiedDate)

坑二:”唯一索引的分区依据列必须是索引键的子集”

即使上述方法修改了执行语句,还是会报错,只是报错的内容不再是约束有关,而是唯一索引的分区依据列必须是索引键的子集。

消息1908,级别16,状态1,第2 行

列‘ModifiedDate‘ 是索引‘PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID‘ 的分区依据列。唯一索引的分区依据列必须是索引键的子集。

也就是说,如果要在唯一索引重建时分区,必须要求分区的依据列是唯一索引的一部分。

如此看来,要想通过重建聚集索引的方式对表进行分区,需要满足如下2个条件中的任意一个:

1. 将分区列添加到索引中;

不过,很多时候分区依据列是datetime类型的字段,作为索引的可选择性不强,将其添加到索引中并不满足索引创建的最佳实践。

2. 索引没有被显示标记为unique且不存在主键约束;

这样就不存在唯一索引的说法,也就不需要分区的依据列是唯一索引的一部分;

不过,在实际场景中,如果表的索引在创建时被显示指定为unique了,还是有办法通过索引“重建”进行分区的,只不过不能使用在线索引重建的方法,我们必须先手动删除索引,然后再来创建非unique的索引。这种方式相比在线重建索引性能要差很多,因为删除一个聚集索引时,SQL Server必须重建每一个非聚集索引(假设存在非聚集索引),从而将其书签修改为RID,然后,在创建聚集索引时,又需要将每个非聚集索引的RID更改书签。

至于主键约束的限制,相比较而言就比较简单了,即使表中存在主键约束,删除它时也不会存在性能上的影响。

时间: 2024-10-10 23:50:22

对已存在的表进行分区时遇到的坑的相关文章

MySQL 已有大数据量表进行分区踩坑

一.背景mysql 表中已有 4 亿数据,为提高查询效率,需创建分区,一开始计划是创建 HASH 分区,结果报错:ERROR 1659 (HY000): Field 'partno' is of a not allowed type for this type of partitioning1 查询得知报错原因,HASH 分区只支持数字分区,而我要分区的字段是 varchar 类型,故改用 KEY 分区二.解决 KEY 分区语句: alter table TABLENAME PARTITION

对已有表进行分区

目标数据库:BOEE 分区表:CB_PRODUCT 分区字段:ID 主要步骤:对于已经存在的表,我们可以采取以下步骤来对其创建分区表 1.添加文件组 2.设置默认的文件组 3.创建分区函数     4.创建分区架构并关联到分区函数     5.删除已经存在的聚集索引(我这里是主键,取消主键约束即删除了索引)     6.基于分区架构重建聚集索引 --修改数据库,创建文件组 ALTER DATABASE BOEE ADD FILEGROUP FG10000 GO ALTER DATABASE BO

mysql 分表与分区

一.操作环境 数据达到百w甚于更多的时候,我们的mysql查询将会变得比较慢, 如果再加上连表查询,程序可能会卡死.即使你设置了索引并在查询中使用到了索引,查询还是会慢.这时候你就要考虑怎么样来提高查询速度了. 抛弃其他的不讲,只从mysql本身的优化来讲,我所知道的方法有三种:mysql集群,mysql分表,mysql分区 二.mysql集群 mysql集群成本比较高,不过这不是这里讲的重点,后期开一篇文章,专门来讲这方面的知识. 三.mysql分表 1. 当数据达到百w,千w的时候,我们就想

mysql数据库为什么要分表和分区?

一般下载的源码都带了MySQL数据库的,做个真正意义上的网站没数据库肯定不行. 数据库主要存放用户信息(注册用户名密码,分组,等级等),配置信息(管理权限配置,模板配置等),内容链接(html ,图片,声音,视频等等的路径).那mysql数据库为什么要分表和分区? 为什么要分表和分区? 我们的数据库数据越来越大,随之而来的是单个表中数据太多.以至于查询书读变慢,而且 由于表的锁机制导致应用操作也搜到严重影响,出现了数据库性能瓶颈. mysql 中有一种机制是表锁定和行锁定,是为了保证数据的完整性

hive中的表、外部表、分区和桶的理解

一.概念介绍 Hive 没有专门的数据存储格式,也没有为数据建立索引,用户可以非常自由的组织 Hive 中的表,只需要在创建表的时候告诉 Hive 数据中的列分隔符和行分隔符,Hive 就可以解析数据 Hive 中的 Table 和数据库中的 Table 在概念上是类似的,每一个 Table 在 Hive 中都有一个相应的目录存储数据.例如,一个表 pvs,它在 HDFS 中的路径为:/wh/pvs,其中,wh 是在 hive-site.xml 中由 ${hive.metastore.wareh

mysql分表和分区简述

1)分表目的:提升对海量数据的进行存取操作的效率选择合适的分表策略,确定分表策略后,当进行数据存取操作时,需求确定要到那张表里去查询数据分表字段:互联网的系统使用用户id字段数据是放到哪个表:分表的字段%分表的数量策略:根据范围分区(表ID 1~200 db1 表ID 201~200 db2 表ID m~n dbn) 范围应该连续但是不连续,使用PAPRTION BY RANGE VALUES LESS THAN关键字不使用COLUMNS关键字时,RANGE中必须为整数字段名或返回确定整数字段的

分析Hive表和分区的统计信息(Statistics)

类似于Oracle的分析表,Hive中也提供了分析表和分区的功能,通过自动和手动分析Hive表,将Hive表的一些统计信息存储到元数据中. 表和分区的统计信息主要包括:行数.文件数.原始数据大小.所占存储大小.最后一次操作时间等: 新表的统计信息 对于一个新创建的表,默认情况下,如果通过INSERT OVERWRITE的方式插入数据,那么Hive会自动将该表或分区的统计信息更新到元数据. 有一个参数来控制是否自动统计,hive.stats.autogather,默认为true. 举例来说: 先创

HBase表预分区

HBase 预分区 在创建HBase表的时候默认一张表只有一个region,所有的put操作都会往这一个region中填充数据,当这个一个region过大时就会进行split.如果在创建HBase的时候就进行预分区则会减少当数据量猛增时由于region split带来的资源消耗. HBase表的预分区需要紧密结合业务场景来选择分区的key值,每个region都有一个startKey和一个endKey来表示该region存储的rowKey范围. 创建包含预分区表的命令如下: > create 't

如何恢复oracle中已删除的表

在9i中Oracle引入了flashback的概念,可以将数据返回到某个时间点,但对于诸如drop/truncate等DDL语句却尚不支持.进入Oracle10g,这一缺陷得到了弥补.可以将丢失掉的表,通过flashback命令直接找回.非常简单且易用. 1.首先,可以查看当前schema中的表: SQL> select * from tab; TNAME                    TABTYPE  CLUSTERID ------------------------ -------