|
| 1 | +--- |
| 2 | +title: "Resumable add table constraints" |
| 3 | +description: New resumable capabilities to support pausing and resuming a running ALTER TABLE ADD CONSTRAINT operation. |
| 4 | +ms.custom: "" |
| 5 | +ms.date: "05/24/2022" |
| 6 | +ms.prod: sql |
| 7 | +ms.reviewer: "" |
| 8 | +ms.technology: security |
| 9 | +ms.topic: conceptual |
| 10 | +author: VanMSFT |
| 11 | +ms.author: vanto |
| 12 | +monikerRange: ">=sql-server-ver16||>= sql-server-linux-ver16" |
| 13 | +--- |
| 14 | + |
| 15 | +# Resumable add table constraints |
| 16 | + |
| 17 | +[!INCLUDE [SQL Server 2022](../../includes/applies-to-version/sqlserver2022.md)] |
| 18 | + |
| 19 | +Starting with SQL Server 2022, resumable operations for online index creation and rebuild are supported. The resumable operations allow index operations to be executed while the table is [online](/sql/t-sql/statements/alter-table-transact-sql#with--online--on--off-as-applies-to-altering-a-column) (`ONLINE=ON`) and also: |
| 20 | + |
| 21 | +- Pause and restart an index create or rebuild operation multiple times to fit a maintenance window |
| 22 | + |
| 23 | +- Recover from index creation or rebuild failures, such as database failovers or running out of disk space. |
| 24 | + |
| 25 | +- Enable truncation of transaction logs during an index creation or rebuild operation. |
| 26 | + |
| 27 | +- When an index operation is paused, both the original index and the newly created one require disk space and need to be updated during [Data Manipulation Language (DML)](/sql/t-sql/statements/statements#data-manipulation-language) operations. |
| 28 | + |
| 29 | +The new SQL Server extensions allow a resumable operation for the [Data Definition Language (DDL)](/sql/t-sql/statements/statements#data-definition-language) command [ALTER TABLE ADD CONSTRAINT](/sql/t-sql/statements/alter-table-transact-sql) and adding a Primary or Unique Key. For more information on adding a Primary or Unique Key, see [ALTER TABLE table_constraint](/sql/t-sql/statements/alter-table-table-constraint-transact-sql). |
| 30 | + |
| 31 | +## Resumable operations |
| 32 | + |
| 33 | +In previous versions of SQL Server, the `ALTER TABLE ADD CONSTRAINT` operation can be executed with the `ONLNE=ON` option. However, the operation may take many hours for a large table to complete, and can consume a great number of resources. There's also the possibility of failures or interruption during such execution. We've introduced resumable capabilities to `ALTER TABLE ADD CONSTRAINT` for users to pause the operation during a maintenance window, or to restart it from where it was interrupted during an execution failure, without restarting the operation from the beginning. |
| 34 | + |
| 35 | +## Supported scenarios |
| 36 | + |
| 37 | +The new resumable capability for `ALTER TABLE ADD CONSTRAINT` supports the following customer scenarios: |
| 38 | + |
| 39 | +- Pause or resume running `ALTER TABLE ADD CONSTRAINT` operation, such as pausing it for a maintenance window, and resuming the operation once the maintenance window is complete. |
| 40 | + |
| 41 | +- Resume `ALTER TABLE ADD CONSTRAINT` operation after failovers and system failures. |
| 42 | + |
| 43 | +- Executing `ALTER TABLE ADD CONSTRAINT` operation on a large table despite the small log size available. |
| 44 | + |
| 45 | +> [!NOTE] |
| 46 | +> The resumable operation for `ALTER TABLE ADD CONSTRAINT` requires the `ALTER` command to be executed online (`WITH ONLINE = ON`). |
| 47 | +
|
| 48 | +This feature is especially useful for large tables. |
| 49 | + |
| 50 | +## T-SQL Syntax for ALTER TABLE |
| 51 | + |
| 52 | +For information on the syntax used to enable resumable operations on a table constraint, see the syntax and options in [ALTER TABLE (Transact-SQL)](/sql/t-sql/statements/alter-table-transact-sql#resumable). |
| 53 | + |
| 54 | +### Remarks for ALTER TABLE |
| 55 | + |
| 56 | +- A new clause **WITH <resumable_options** have been added to the current T-SQL syntax in [ALTER TABLE (Transact-SQL)](/sql/t-sql/statements/alter-table-transact-sql). |
| 57 | + |
| 58 | +- The option **RESUMABLE** is new and has been added to the existing [ALTER TABLE (Transact-SQL)](/sql/t-sql/statements/alter-table-transact-sql) syntax. |
| 59 | + |
| 60 | +- `MAX_DURATION` = *time* \[MINUTES\] used with `RESUMABLE = ON` (requires `ONLINE = ON`). `MAX_DURATION` indicates time (an integer value specified in minutes) that a resumable online add constraint operation is executed before being paused. If not specified, the operation continues until completion. |
| 61 | + |
| 62 | +## T-SQL syntax for ALTER INDEX |
| 63 | + |
| 64 | +To pause, resume, or abort the resumable table constraint operation for `ALTER TABLE ADD CONSTRAINT`, use the T-SQL syntax [ALTER INDEX (Transact-SQL)](/sql/t-sql/statements/alter-index-transact-sql). |
| 65 | + |
| 66 | +For resumable constraints the existing ALTER INDEX ALL command is used. |
| 67 | + |
| 68 | +```syntaxsql |
| 69 | +ALTER INDEX ALL ON <table_name> |
| 70 | + { RESUME [WITH (<resumable_index_options>,[...n])] |
| 71 | + | PAUSE |
| 72 | + | ABORT |
| 73 | + } |
| 74 | +<resumable_index_option> ::= |
| 75 | + { |
| 76 | + MAXDOP = max_degree_of_parallelism |
| 77 | + | MAX_DURATION =<time> [MINUTES] |
| 78 | + | <low_priority_lock_wait> |
| 79 | + } |
| 80 | + <low_priority_lock_wait>::= |
| 81 | +{ |
| 82 | + WAIT_AT_LOW_PRIORITY ( MAX_DURATION = <time> [ MINUTES ] , |
| 83 | + ABORT_AFTER_WAIT = { NONE | SELF | BLOCKERS } ) |
| 84 | +} |
| 85 | +``` |
| 86 | + |
| 87 | +### Remarks for ALTER INDEX |
| 88 | + |
| 89 | +`ALTER INDEX ALL ON <Table> PAUSE` |
| 90 | + |
| 91 | +- Pause a resumable and online add table constraint operation that is being executed |
| 92 | + |
| 93 | +`ALTER INDEX ALL ON <Table> RESUME [WITH (<resumable_index_options>,[...n])]` |
| 94 | + |
| 95 | +- Resume an add table constraint operation that is paused manually or due to a failure. |
| 96 | + |
| 97 | +`MAX_DURATION` used with `RESUMABLE=ON ` |
| 98 | + |
| 99 | +- The time (an integer value specified in minutes) that the resumable add table constraint operation is executed after being resumed. Once the time expires, the resumable operation is paused if it's still running. |
| 100 | + |
| 101 | +`WAIT_AT_LOW_PRIORITY` used with `RESUMABLE=ON` and `ONLINE = ON` |
| 102 | + |
| 103 | +- Resuming an online add table constraint operation after a pause must wait for blocking operations on this table. `WAIT_AT_LOW_PRIORITY` indicates that the add table constraint operation will wait for low priority locks, allowing other operations to proceed while the resumable operation is waiting. Omitting the `WAIT_AT_LOW_PRIORITY` option is equivalent to `WAIT_AT_LOW_PRIORITY (MAX_DURATION = 0 minutes, ABORT_AFTER_WAIT = NONE)`. For more information, see [WAIT_AT_LOW_PRIORITY](/sql/t-sql/statements/alter-index-transact-sql#wait-at-low-priority). |
| 104 | + |
| 105 | +`ALTER INDEX ALL ON <Table> ABORT` |
| 106 | + |
| 107 | +- Abort a running or paused add table constraint operation that was declared as resumable. The abort operation must be explicitly executed as an `ABORT` command to terminate a resumable constraint operation. Failure or pausing a resumable table constraint operation doesn't terminate its execution. Rather, it leaves the operation in an indefinite paused state. |
| 108 | + |
| 109 | +For more information on `PAUSE`, `RESUME`, and `ABORT` options available for resumable operations, see [ALTER INDEX (Transact-SQL)](/sql/t-sql/statements/alter-index-transact-sql). |
| 110 | + |
| 111 | +## View the status for resumable operation |
| 112 | + |
| 113 | +To view the status for the resumable table constraint operation, use the view [sys.index_resumable_operations](/sql/relational-databases/system-catalog-views/sys-index-resumable-operations). |
| 114 | + |
| 115 | +## Permissions |
| 116 | + |
| 117 | +Requires `ALTER` permission on the table. |
| 118 | + |
| 119 | +No new permissions for resumable `ALTER TABLE ADD CONSTRAINT` are required. |
| 120 | + |
| 121 | +## Examples |
| 122 | + |
| 123 | +Here are some examples on using resumable add table constraint operations. |
| 124 | + |
| 125 | +### Example 1 |
| 126 | + |
| 127 | +Resumable `ALTER TABLE` operation for adding a primary key clustered on column (a) with `MAX_DURATION` of 240 minutes. |
| 128 | + |
| 129 | +```sql |
| 130 | +ALTER TABLE table1 |
| 131 | +ADD CONSTRAINT PK_Constrain PRIMARY KEY CLUSTERED (a) |
| 132 | +WITH (ONLINE = ON, MAXDOP = 2, RESUMABLE = ON, MAX_DURATION = 240); |
| 133 | +``` |
| 134 | + |
| 135 | +### Example 2 |
| 136 | + |
| 137 | +Resumable `ALTER TABLE` operation for adding a unique constraint on two columns (a and b) with `MAX_DURATION` of 240 minutes. |
| 138 | + |
| 139 | +```sql |
| 140 | +ALTER TABLE table2 |
| 141 | +ADD CONSTRAINT PK_Constrain UNIQUE CLUSTERED (a,b) |
| 142 | +WITH (ONLINE = ON, MAXDOP = 2, RESUMABLE = ON, MAX_DURATION = 240); |
| 143 | +``` |
| 144 | + |
| 145 | +### Example 3 |
| 146 | + |
| 147 | +`ALTER TABLE` operation for adding a primary key clustered being paused and resumed. |
| 148 | + |
| 149 | +The table below shows two sessions (`Session #1` and `Session #2`) being executed chronologically using the following T-SQL statements. `Session #1` executes a resumable `ALTER TABLE ADD CONSTRAINT` operation creating a primary key on column `Col1`. `Session #2` checks the execution status for the running constraint. After some time, it pauses the reusable operation. `Session #2` checks the status for the paused constraint. Finally, `Session #1` resumes the paused constraint and `Session #2` checks the status again. |
| 150 | + |
| 151 | +|Session #1|Session #2| |
| 152 | +|-----|-----| |
| 153 | +|Execute resumable add constraint <br><br> `ALTER TABLE TestConstraint` <br> `ADD CONSTRAINT PK_TestConstraint PRIMARY KEY (Col1)` <br> `WITH (ONLINE = ON, MAXDOP = 2, RESUMABLE = ON, MAX_DURATION = 30);`|| |
| 154 | +||Check the constraint status <br><br> `SELECT sql_text, state_desc, percent_complete` <br> `FROM sys.index_resumable_operations;`| |
| 155 | +|Output showing the operation <br><br> <table border="1"><tr><td>**sql_text**</td><td>**state_desc**</td><td>**percent_complete**</td></tr><tr><td>`ALTER TABLE TestConstraint (...)`</td><td>RUNNING</td><td>43.552</td></tr></table>|| |
| 156 | +||Pause the resumable constraint <br><br> `ALTER INDEX ALL ON TestConstraint PAUSE;`| |
| 157 | +|**Error** <br><br> `Msg 1219, Level 16, State 1, Line 6` <br> `Your session has been disconnected because of a high priority DDL operation.` <br><br> `Msg 1750, Level 16, State 1, Line 6` <br> `Could not create constraint or index. See previous errors.` <br><br> `Msg 0, Level 20, State 0, Line 5` <br> `A severe error occurred on the current command.` <br> `The results, if any, should be discarded.`|| |
| 158 | +||Check the constraint status <br><br> `SELECT sql_text, state_desc, percent_complete` <br> `FROM sys.index_resumable_operations;`| |
| 159 | +|Output showing the operation <br><br> <table border="1"><tr><td>**sql_text**</td><td>**state_desc**</td><td>**percent_complete**</td></tr><tr><td>`ALTER TABLE TestConstraint (...)`</td><td>PAUSED</td><td>65.339</td></tr></table>|| |
| 160 | +|`ALTER INDEX ALL ON TestConstraint RESUME;`|| |
| 161 | +||Check the constraint status <br><br> `SELECT sql_text, state_desc, percent_complete` <br> `FROM sys.index_resumable_operations;`| |
| 162 | +|Output showing the operation <br><br> <table border="1"><tr><td>**sql_text**</td><td>**state_desc**</td><td>**percent_complete**</td></tr><tr><td>`ALTER TABLE TestConstraint (...)`</td><td>RUNNING</td><td>90.238</td></tr></table>|| |
| 163 | + |
| 164 | +Once the operation is completed, execute the following T-SQL statement to check the constraint: |
| 165 | + |
| 166 | +```sql |
| 167 | +SELECT constraint_name, table_name, constraint_type |
| 168 | +FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE='PRIMARY KEY'; |
| 169 | +GO |
| 170 | +``` |
| 171 | + |
| 172 | +Here's the result set: |
| 173 | + |
| 174 | +|constraint_name|table_name|constraint_type| |
| 175 | +|-----|-----|-----| |
| 176 | +|PK_Constraint|TestConstraint|PRIMARY KEY| |
| 177 | + |
| 178 | +## See also |
| 179 | + |
| 180 | +- [Guidelines for Online Index Operations](/sql/relational-databases/indexes/guidelines-for-online-index-operations) |
| 181 | +- [CREATE INDEX (Transact-SQL)](/sql/t-sql/statements/create-index-transact-sql) |
| 182 | +- [ALTER INDEX (Transact-SQL)](/sql/t-sql/statements/alter-index-transact-sql) |
| 183 | +- [sys.index_resumable_operations](/sql/relational-databases/system-catalog-views/sys-index-resumable-operations) |
| 184 | +- [WAIT_AT_LOW_PRIORITY](/sql/t-sql/statements/alter-index-transact-sql#wait-at-low-priority) |
| 185 | +- [ALTER TABLE (Transact-SQL)](/sql/t-sql/statements/alter-table-transact-sql) |
| 186 | +- [ALTER TABLE index_option](/sql/t-sql/statements/alter-table-index-option-transact-sql) |
0 commit comments