更改分区列的排序规则 (SQL Server 2017)

Mik*_*nov 6 sql-server collation partitioning

我正在尝试更改列的排序规则:

ALTER TABLE [dbo].[yourdad] ALTER COLUMN [yourmam] varchar(36) COLLATE SQL_Latin1_General_CP1_CI_AI NOT NULL; 
Run Code Online (Sandbox Code Playgroud)

它给出了这样的消息:

消息 5074,级别 16,状态 1,第 1 行 对象“yourdad”依赖于列“yourmam”。消息 4922,级别 16,状态 9,第 1 行 ALTER TABLE ALTER COLUMN yourmam 失败,因为一个或多个对象访问此列。

它具有依赖于该列的分区模式和功能。

目前我喜欢超过 40k 的表,其中包含应该更改排序规则的列。

是否可以在不重新创建表格的情况下更改排序规则?

  1. 删除分区索引 - 删除。

  2. 但是当我尝试删除架构时:

    删除分区方案你爸爸

消息 7717,级别 16,状态 1,第 1 行 分区方案“yourdad”当前正用于对一个或多个表进行分区。

这是我不想安装的数据库上的一种新的不区分大小写的数据库整理,旧的是 - 区分大小写。

Sol*_*zky 7

您不需要删除表。

一种选择(我已经测试过)是:

  1. 删除分区的非聚集索引;将分区聚集索引、主键和唯一约束移动到非分区文件组;通过在未分区的文件组上创建(临时)聚集索引来取消对堆的分区。有关确定哪些索引受到影响以及需要对每个索引采取哪些操作的帮助,请参阅我在“更改实例、数据库和所有列的排序规则”“查找和修复被忽略的对象”部分中发布的查询在所有用户数据库中:可能出现什么问题?” (其中还包含处理聚集索引、约束和堆的示例)。
  2. 删除分区方案
  3. 删除分区函数
  4. 使用新的排序规则更改列定义
  5. 删除并重新创建分区函数以使用COLLATE输入参数的新排序规则指定子句(这里假设您没有更改数据库的默认排序规则,并且输入参数将使用数据库的字符串类型默认排序规则,除非指定使用该COLLATE条款,并CREATE INDEX使用该方案和功能,如果该参数的排序规则不匹配的分区列的排序规则将失败语句)。意思是,如果您将列的排序规则更改为SQL_Latin1_General_CP1_CI_AI但数据库仍在使用SQL_Latin1_General_CP1_CI_AS,那么您需要:

    CREATE PARTITION FUNCTION PartitionFunc
    (
      VARCHAR(36) COLLATE SQL_Latin1_General_CP1_CI_AI
    )
    ...
    
    Run Code Online (Sandbox Code Playgroud)

现在,40k+ 个表可能不止几个,但如果它们都使用相同的分区方案和功能,那么与您已经需要的相比,这只是 4 个额外的语句(为分区模式和分区功能创建和删除)即使没有使用分区(即,无论如何您都需要删除并重新创建索引)。因此,虽然这在删除和重新创建索引时确实需要大量 I/O,但在更改列的排序规则时无法解决这个问题。

我假设(并且手指交叉)这些列不是

  • 聚集索引的一部分
  • 外键的主键或唯一索引/约束中的键字段

如果其中任何一种情况属实,那么您还有很多工作要做,但这与分区无关。


另一种选择(考虑到不想重新创建所有内容)可能是使用未记录的sqlservr.exe -q选项来更改实例上所有用户列和数据库的排序规则。这种方法会更改数据库、列、参数等的元数据,然后重建索引(同样,在更改排序规则时无法解决此问题,因此对于 40k+ 表,这可能需要几分钟(或更长时间)并且数据库或整个实例(如果您全局更新排序规则)在此期间将处于脱机状态)。

我只是测试上的SQL Server 2019 RC1这种情况下,它也不能对分区功能的工作,但是,这并不意味着,这种做法是不是整体解决方案的一部分。这只是意味着你真的别无选择,只能完成上一节中提到的过程。该SQLSERVR.EXE -q方法将处理一切(除用户定义的表类型,我相信)。能够更改列的排序规则有很多限制,更改数据库的默认排序规则(两种情况下都有很多依赖项)的限制更多,所以如果您现在想要一个区分大小写的数据库,那么您可能会除了分区列之外还有其他障碍。

不适用于分区函数的是输入参数的排序规则存储在sys.partition_parameters. 这个特殊的元数据不会被其他很棒的甚至如果未记录的-q选项改变。这样做的效果是:

  1. 假设数据要么VARCHAR没有更改代码页,要么NVARCHAR,那么数据仍将像以前一样进行分区。例如,假设您有一个RANGE LEFT使用FOR VALUES ( 'D', 'H', 'O', 'V' ). 在这种情况下,分区 #2 包含值> D<= H

    • 当使用 的不区分大小写的排序规则时SQL_Latin1_General_CP1_CI_AI,分区 #2 将包含E, e, F, f, G, g, H, h。够简单了吧?
    • 但是,当使用区分大小写的排序规则时SQL_Latin1_General_CP1_CS_AI,分区 #2 将包含d, E, e, F, f, G, g, H。此分区现在包含小写d,不包含小写h。这是因为大多数 SQL Server 排序规则在小写之前排序大写(Windows 排序规则首先排序小写)。
  2. 如果数据VARCHAR和代码页不同,那么事情可能会变得有趣。值在 128 和 255 之间的任何字符都可能具有不同的值和/或排序位置,被映射到类似的字符,因为它在用于分区函数整理的整理代码页上不可用(即“最佳拟合”映射),或者它可能在旧代码页中丢失,因此它变成了一个“ ? ”并按那个排序。根据正在使用的字符、它们如何映射(如果它们甚至这样做)到另一个代码页以及如何设置分区范围,您可能会遇到从“根本没有影响”到“非常奇怪和困难”的任何事情跟踪/调试行为”。

我已经提交了将这个特定的元数据添加到sqlservr.exe -q操作的请求,但微软没有真正的动力来修复它,因为它是一个未记录的功能。所以,请支持它(即投票给它),这样他们至少可以看到人们确实想要它(谢谢!): 通过 SQLSERVR -Q 更新分区函数和用户定义表类型的排序规则

话虽如此,两个主要问题是:

  1. 首先更改排序规则有什么影响?什么是当前归类,什么是新归类?

    如果代码页正在更改,是否会丢失数据(问题中的示例代码显示了一个VARCHAR列,这使得这种情况成为可能;对于 而言并非如此NVARCHAR)?这种方法并没有做一个代码页转换,所以用128和255之间的值的字符可能会成为一些其它字符,并且没有警告/当这种情况发生的错误(但如果你没有这样的数据,那么这是一个非-问题)。

    如果敏感度发生变化(即从 Accent-Sensitive 变为 Accent-Insensitive),那么现在是否会违反现有唯一索引/约束中的唯一性?

  2. 您想要用于所有内容的新排序规则吗?如果是这样,这可能会奏效。如果不是,那么这种方法是不可行的,因为它改变了一切。

有关此方法的完整详细信息,请参阅我的帖子:

更改所有用户数据库中的实例、数据库和所有列的排序规则:可能出现什么问题?(请务必查看“查找和修复被忽略的对象”部分,其中包含帮助修复分区功能的查询)

如果您有多个数据库并且只想更改这个数据库(同样,此数据库中的所有内容,包括数据库的默认排序规则),那么您可以:

  1. 分离(或备份)此数据库。
  2. 创建一个新的临时实例,仅用于进行此更改,使用与该数据库当前所属的实例相同的实例级排序规则。
  3. 将数据库附加(或恢复)到新的临时实例。
  4. 使用sqlservr.exe -q方法更新临时实例的排序规则。
  5. 从临时实例中分离(或备份)数据库。
  6. 将数据库重新附加(或恢复)到它来自的实例。