如何从表中删除分区?

Posted

技术标签:

【中文标题】如何从表中删除分区?【英文标题】:How does one Remove a Partition from a Table? 【发布时间】:2019-04-18 14:33:59 【问题描述】:

我已设法将分区添加到表(日志)中,但需要创建回滚脚本以防需要将其删除。不幸的是,这现在已经失败,并且由于回滚脚本的中途失败,日志现在没有主键,我无法在收到错误时将其添加回来......

列“SuperLogId”是索引“PK__Logs__0E6B88F2”的分区列。唯一索引的分区列必须是索引键的子集。

尝试运行时:

ALTER TABLE dbo.Logs
ADD PRIMARY KEY CLUSTERED (Id ASC)

所以我尝试按照本指南 (https://www.patrickkeisler.com/2013/01/how-to-remove-undo-table-partitioning.html) 进行操作,最终不得不编写此指南以生成脚本来合并我所有动态创建的分区。

DECLARE @partitionsTable dbo.NVarCharCollectionTableType --User-defined table type to hold a collection of NVarChars.

INSERT INTO @partitionsTable
SELECT CONCAT('ALTER PARTITION FUNCTION Logs_SuperLogId_PartitionFunction() MERGE RANGE (', CONVERT(NVARCHAR, [Value]), ')')
FROM SYS.PARTITION_SCHEMES
INNER JOIN SYS.PARTITION_FUNCTIONS ON PARTITION_FUNCTIONS.FUNCTION_ID = PARTITION_SCHEMES.FUNCTION_ID
INNER JOIN SYS.PARTITION_RANGE_VALUES ON PARTITION_RANGE_VALUES.FUNCTION_ID = PARTITION_FUNCTIONS.FUNCTION_ID
WHERE PARTITION_SCHEMES.Name = 'Logs_SuperLogId_PartitionScheme'
AND PARTITION_FUNCTIONS.Name = 'Logs_SuperLogId_PartitionFunction'
ORDER BY [Value] ASC

DECLARE @statement NVARCHAR(MAX)

SELECT @statement =
    CASE
        WHEN @statement IS NULL
        THEN CAST([Text] AS NVARCHAR(MAX))
        ELSE CONCAT(@statement, '; ', [Text])
    END
    FROM @partitionsTable
    ORDER BY [Text] ASC

SELECT @statement

EXECUTE SP_EXECUTESQL @statement

ALTER PARTITION SCHEME Logs_SuperLogId_PartitionScheme NEXT USED [PRIMARY]

指南建议这会有所帮助,但它没有!尝试重新添加主键时仍然遇到相同的错误,并且尝试删除分区功能和分区方案时仍然遇到这些错误!

DROP PARTITION SCHEME Logs_SuperLogId_PartitionScheme

分区方案“Logs_SuperLogId_PartitionScheme”当前用于对一个或多个表进行分区。

DROP PARTITION FUNCTION CatLogs_CatSessionLogId_PartitionFunction

一个或多个分区方案正在使用分区函数“Logs_SuperLogId_PartitionFunction”。

我的分区方案如何仍在使用?为什么我不能摆脱它而不再使用它?我只想对我的 Logs 表进行去分区并重新添加其原始聚集主键(我之前必须将其删除并替换为非聚集主键以使 SuperLogId 在其上具有聚集索引,以便可以对其进行分区)。

更新:

我能够使用以下 hack 将分区从我的表中删除,但我仍然无法删除分区方案或函数。

--HACK: Dummy Index to disassociate the table from the partitioning scheme.
CREATE CLUSTERED INDEX IX_Logs_Id ON dbo.Logs(Id) ON [Primary]

--Now that the table has been disassociated with the partition, this dummy index can be dropped.
DROP INDEX IX_Logs_Id ON dbo.Logs

我已经运行了这个脚本来找出哪些表正在使用我的数据库中的任何分区,它没有返回任何内容,正如预期的那样。

SELECT DISTINCT TABLES.NAME
FROM SYS.PARTITIONS
INNER JOIN SYS.TABLES ON PARTITIONS.OBJECT_ID = TABLES.OBJECT_ID
WHERE PARTITIONS.PARTITION_NUMBER <> 1

这允许我重新添加主键,但在尝试删除分区方案时我仍然收到 The partition scheme "Logs_SuperLogId_PartitionScheme" is currently being used... 错误。

根据 Microsoft 文档 (https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-partition-scheme-transact-sql?view=sql-server-2017),如果没有表或索引引用分区方案,则它应该是可删除的。因此,我随后也运行了这个脚本来检查使用它的索引...

SELECT DISTINCT indexes.NAME
FROM SYS.PARTITIONS
INNER JOIN SYS.indexes ON indexes.index_id = partitions.index_id
WHERE PARTITIONS.PARTITION_NUMBER <> 1

...它什么也没返回!那么到底在使用我的分区方案是什么?!

【问题讨论】:

最简单的迁移方法是什么? 【参考方案1】:

我能够使用以下代码从其表中删除分区。

--HACK: Dummy Index to disassociate the table from the partitioning scheme.
CREATE CLUSTERED INDEX IX_Logs_Id ON dbo.Logs(Id) ON [Primary]

--Now that the table has been disassociated with the partition, this dummy index can be dropped.
DROP INDEX IX_Logs_Id ON dbo.Logs

然后,使用以下脚本,发现两个索引仍在分区方案上。

SELECT SCHEMA_NAME(B.SCHEMA_ID) SCHEMANAME, B.NAME TABLENAME, C.INDEX_ID, C.NAME INDEXNAME, C.TYPE_DESC,
A.PARTITION_NUMBER, D.NAME DATASPACENAME, F.NAME SCHEMADATASPACENAME,
H.VALUE DATARANGEVALUE, A.ROWS,
J.IN_ROW_RESERVED_PAGE_COUNT, J.LOB_RESERVED_PAGE_COUNT,
J.IN_ROW_RESERVED_PAGE_COUNT+J.LOB_RESERVED_PAGE_COUNT TOTALPAGECOUNT,
I.LOCATION
FROM SYS.PARTITIONS A
JOIN SYS.TABLES B ON A.OBJECT_ID = B.OBJECT_ID
JOIN SYS.INDEXES C ON A.OBJECT_ID = C.OBJECT_ID AND A.INDEX_ID = C.INDEX_ID
JOIN SYS.DATA_SPACES D ON C.DATA_SPACE_ID = D.DATA_SPACE_ID
LEFT JOIN SYS.DESTINATION_DATA_SPACES E ON E.PARTITION_SCHEME_ID = D.DATA_SPACE_ID AND A.PARTITION_NUMBER = E.DESTINATION_ID
LEFT JOIN SYS.DATA_SPACES F ON E.DATA_SPACE_ID = F.DATA_SPACE_ID 
LEFT JOIN SYS.PARTITION_SCHEMES G ON D.NAME = G.NAME
LEFT JOIN SYS.PARTITION_RANGE_VALUES H ON G.FUNCTION_ID = H.FUNCTION_ID AND H.BOUNDARY_ID = A.PARTITION_NUMBER
LEFT JOIN (SELECT DISTINCT DATA_SPACE_ID, LEFT(PHYSICAL_NAME, 1) LOCATION FROM SYS.DATABASE_FILES) I ON I.DATA_SPACE_ID = ISNULL(F.DATA_SPACE_ID, D.DATA_SPACE_ID)
LEFT JOIN SYS.DM_DB_PARTITION_STATS J ON J.OBJECT_ID = A.OBJECT_ID AND J.INDEX_ID = A.INDEX_ID AND J.PARTITION_NUMBER = A.PARTITION_NUMBER
ORDER BY 1, 2, 3, A.PARTITION_NUMBER

我所要做的就是删除引用分区方案的两个索引,然后删除分区方案,然后删除分区函数。

【讨论】:

像往常一样,我正在寻找一个简单的命令,例如 'ALTER TABLE tblName DROP ....[something]' :D

以上是关于如何从表中删除分区?的主要内容,如果未能解决你的问题,请参考以下文章

oracle删除分区还在编辑表中显示吗为啥

从 hive 外部表中的分区中删除列

从 HDFS 中删除分区目录,它会反映在 hive 表中吗?

从 Hive 分区外部表中删除特定列

从 redshift 中删除外部表的所有分区

jooq 从表的特定分区中选择