将 nvarchar(max) 列更改为 nvarchar(50) 会锁定表吗?

Chr*_*art 6 sql-server datatypes alter-table azure-sql-database

我在 SQL Server (Azure) 中有一个包含 140 万行的表。

我想索引其中一列;但是,它的数据类型是nvarchar(max)(通过使用我想象的 EF 默认为这样)。我正在使用实体框架,并且可以进行迁移,将此数据类型更改为nvarchar(50).

我担心这需要多长时间,以及是否会导致锁定问题。我只扩展过列,所以我不确定会发生什么。我确实知道此列中的数据适合新尺寸。

我正计划创建数据库的副本并尝试一下。我也考虑过迁移到一个新列,但如果不是太痛苦,我更愿意更新当前列。

Joe*_*ish 9

我们无法完全回答您的问题。取决于太多因素,包括表定义、表中的其他列、数据是否离页、ORM 生成的 T-SQL 等等。该文档是相当不错的,但:

WITH (ONLINE = ON | OFF) 适用于:SQL Server 2016 到 SQL Server 2017 和 Azure SQL 数据库。

允许在表保持可用时执行许多更改列操作。默认为关闭。对于与数据类型、列长度或精度、可空性、稀疏性和排序规则相关的列更改,可以在线执行更改列。

联机更改列允许用户创建和自动统计信息在 ALTER COLUMN 操作期间引用更改的列。这允许查询照常执行。在操作结束时,引用该列的自动统计信息将被删除,用户创建的统计信息将失效。操作完成后,用户必须手动更新用户生成的统计信息。如果该列是任何统计信息或索引的过滤器表达式的一部分,则您无法执行更改列操作。

当联机更改列操作正在运行时,所有可能依赖于列(索引、视图等)的操作都将阻塞或失败并出现相应的错误。这保证了在线更改列不会因为操作运行时引入的依赖关系而失败。

联机更改列与联机索引重建具有类似的要求、限制和功能。这包括:

当表包含旧 LOB 或文件流列或表具有列存储索引时,不支持联机索引重建。相同的限制适用于在线更改列。

被改变的现有列需要两倍的空间分配;对于原始列和新创建的隐藏列。

更改列联机操作期间的锁定策略遵循用于联机索引构建的相同锁定模式。

此外,它的测试也非常简单。我正在使用默认的已提交读隔离级别对 SQL Server 2017 进行测试。首先,我将创建表:

DROP TABLE IF EXISTS dbo.CONVERT_ME;

CREATE TABLE dbo.CONVERT_ME (
    ID BIGINT NOT NULL,
    OVERWEIGHT_COLUMN VARCHAR(MAX) NOT NULL,
    PRIMARY KEY (ID)
);

INSERT INTO dbo.CONVERT_ME WITH (TABLOCK)
SELECT TOP (1500000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), REPLICATE('Z', 50)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)

然后我将更改 column OFFLINE,这是默认值:

SET STATISTICS IO, TIME ON;

BEGIN TRANSACTION;

ALTER TABLE dbo.CONVERT_ME
ALTER COLUMN OVERWEIGHT_COLUMN VARCHAR(50) NOT NULL WITH (ONLINE = OFF);
Run Code Online (Sandbox Code Playgroud)

我的机器这需要大约三秒钟。该操作在整个事务期间采用模式修改锁,以防止对其采用任何其他锁,包括使用NOLOCK.

在此处输入图片说明

现在我将尝试使用 WITH (ONLINE = ON)。该操作现在符合并行性,因此它可能会在您的服务器上运行得更快。模式修改锁仍然在对象上,但它发生在接近尾声而不是在整个事务中。下面是锁表的示例快照,用于显示在大部分事务期间持有的架构修改锁:

在此处输入图片说明

请注意,尚未获取对象级架构修改锁定。这是操作完成后但事务提交之前的样子:

在此处输入图片说明

对象上的模式修改锁定以及其他一些锁定在接近尾声时被简要介绍。

太好了,用了应该没问题WITH (ONLINE = ON)吧?正如我之前所说,手术所需的时间将取决于很多因素。考虑一个不同的表,它有更多的数据页:

DROP TABLE IF EXISTS dbo.CONVERT_ME;

CREATE TABLE dbo.CONVERT_ME (
    ID BIGINT NOT NULL,
    OTHER_COLUMN VARCHAR(8000) NOT NULL,
    OVERWEIGHT_COLUMN VARCHAR(MAX) NOT NULL,
    PRIMARY KEY (ID)
);

INSERT INTO dbo.CONVERT_ME WITH (TABLOCK)
SELECT TOP (1500000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)), REPLICATE('Z', 4200), REPLICATE('Z', 50)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
OPTION (MAXDOP 1);
Run Code Online (Sandbox Code Playgroud)

在我的机器一样ALTER TABLE,现在需要运行时39635个MSOFFLINE和MS 117877在运行时ONLINE

我对您的建议是阅读文档,直到您确信自己了解锁定注意事项,并在生产中进行切换之前,使用填充有真实数据的真实表模式进行测试。

请注意:

不确定 Azure SQL 数据库,但在常规 SQL Server 中,该ONLINE选项仅适用于企业版。尝试在另一个版本中执行此操作将导致以下错误:

Msg 1712, Level 16, State 1, Line XXXXX
在线索引操作只能在 SQL Server 企业版中进行。