我的SQL Server 2008中存在这种情况。
我需要更改列类型,但索引会阻止更改。但是由于数据库位于多个客户端上,我不知道涉及该列的索引有多少。
以编程方式说,有任何方法可以获取涉及该列并删除它们的所有索引,并在alter table
语句自动重新创建它们之后?
我听说禁用它们会使表格变得混乱,因为类型会发生变化。
我正在从tinyint变为smallint类型。
答案 0 :(得分:5)
禁用目标表上的所有索引
ALTER INDEX Indexname ON Table DISABLE
然后改变列的数据类型
ALTER TABLE table
ALTER COLUMN columnname datatype
之后启用索引
ALTER INDEX Indexname ON Table REBUILD
答案 1 :(得分:4)
还尝试通过列名来了解表中的所有索引:
SELECT OBJECT_SCHEMA_NAME(ind.object_id) AS SchemaName
, OBJECT_NAME(ind.object_id) AS ObjectName
, ind.name AS IndexName
, ind.is_primary_key AS IsPrimaryKey
, ind.is_unique AS IsUniqueIndex
, col.name AS ColumnName
, ic.is_included_column AS IsIncludedColumn
, ic.key_ordinal AS ColumnOrder
FROM sys.indexes ind
INNER JOIN sys.index_columns ic
ON ind.object_id = ic.object_id
AND ind.index_id = ic.index_id
INNER JOIN sys.columns col
ON ic.object_id = col.object_id
AND ic.column_id = col.column_id
INNER JOIN sys.tables t
ON ind.object_id = t.object_id
WHERE t.is_ms_shipped = 0
ORDER BY OBJECT_SCHEMA_NAME(ind.object_id) --SchemaName
, OBJECT_NAME(ind.object_id) --ObjectName
, ind.is_primary_key DESC
, ind.is_unique DESC
, ind.name --IndexName
, ic.key_ordinal
答案 2 :(得分:2)
您可以使用以下脚本返回指定表/列的索引名称和类型。:
DECLARE @tableName SYSNAME
DECLARE @columnName SYSNAME
SET @tableName = 'Products'
SET @columnName = 'Name'
SELECT IDX.name, IDX.type_desc, IndexedColumn
FROM sys.tables TBL
INNER JOIN sys.indexes IDX ON TBL.object_id = IDX.object_id
LEFT JOIN sys.filegroups FG ON IDX.data_space_id = FG.data_space_id
CROSS APPLY
( SELECT COLS.Name
FROM sys.index_columns IXCL
INNER JOIN sys.columns COLS
ON IXCL.object_id = COLS.object_id
AND IXCL.column_id = COLS.column_id
WHERE IDX.object_id = IXCL.object_id
AND IDX.index_id = IXCL.index_id
AND COLS.name = @columnName
AND IDX.object_id = OBJECT_ID(@tableName)
) Indexed (IndexedColumn)
WHERE TBL.object_id = OBJECT_ID(@tableName)
希望这有助于......
答案 3 :(得分:2)
您可以使用内置工具完成此项工作。在SQL Server Management Studio中,单击"工具"那么"选项"
展开" SQL Server对象资源管理器"设置并在其中,单击" Scripting"。
向下滚动到"表和视图选项"在右边。
找到名为"脚本索引"的记录并将其设置为" True",然后单击“确定”。
在对象资源管理器中右键单击表时,您可以选择“脚本为...”#34;选择这些选项中的任何一个现在将编写索引以及表本身及其键的脚本。复制所需的脚本,或者根据需要运行整个过程。
答案 4 :(得分:0)
让我们假设基本情况(列不是任何约束的一部分,而不是具有XML索引的XML列等),可以完成以下操作:
select (...) from
<sys.indexes + other sys schema views> FOR XML ...
答案 5 :(得分:0)
以下是安全删除和重新创建索引的示例SQL:
IF(select object_id from sys.indexes where [name] = 'IDX_RecordSubscription' and object_id = OBJECT_ID('[SystemSetup].[RecordSubscription]')) IS NOT NULL
BEGIN
DROP INDEX [SystemSetup].[RecordSubscription].IDX_RecordSubscription
END
GO
CREATE UNIQUE INDEX
IDX_RecordSubscription
ON
[SystemSetup].[RecordSubscription]
(
Subscriber ASC,
MenuItem ASC,
RecordPrimaryKeyGuid ASC
)
WITH
(
PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = OFF
) ON [PRIMARY]
GO
这里有一些C#代码可以解决这个问题:
protected override string GetCreateIndexScript(string uniquePart, string indexName, string fullTableName, string columnsPart)
{
return
$"IF(select object_id from sys.indexes where [name] = '{indexName}' and object_id = OBJECT_ID('{fullTableName}')) IS NOT NULL \r\n" +
"BEGIN \r\n" +
$" DROP INDEX {fullTableName}.{indexName} \r\n " +
"END\r\n\r\n" +
"GO\r\n\r\n" +
$"CREATE {uniquePart} INDEX\r\n" +
$"\t{indexName}\r\n" +
"ON\r\n" +
$"\t{fullTableName}\r\n" +
"\t(\r\n" +
$"\t\t{columnsPart}\r\n" +
"\t)\r\n" +
"\tWITH\r\n" +
"\t(\r\n" +
"\t\tPAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = OFF\r\n" +
"\t) ON [PRIMARY] ";
}
这里有一些C#(可以转换为SQL)来获取索引模式:
const string selectStatement = "select " +
" SCHEMAs.name + '.' + tabs.name as OBJECT_ID, " +
" ind.name as INDEX_NAME, " +
" indcol.index_id AS INDEX_ID, " +
" indcol.key_ordinal AS COLUMN_ORDINAL, " +
" col.name AS COLUMN_NAME, " +
" ind.is_unique " +
"from " +
" sys.indexes ind " +
"inner join " +
" sys.index_columns indcol " +
"on " +
" ind.object_id = indcol.object_id and " +
" ind.index_id = indcol.index_id " +
"inner join " +
" sys.columns col " +
"on " +
" col.object_id = indcol.object_id and " +
" col.column_id = indcol.column_id " +
"inner join " +
" sys.tables tabs " +
"on " +
" tabs.object_id = ind.object_id " +
"inner join " +
" sys.schemas schemas " +
"on " +
" tabs.schema_id = schemas.schema_id " +
"where " +
" ind.type =2 and" +
" tabs.name <> 'sysdiagrams' " +
"order by " +
" tabs.object_id, " +
" indcol.index_id, " +
" indcol.key_ordinal ";
return DatabaseAdapter.Fill(selectStatement, null, null, null);
所以,基本上,你在这里执行最后一段代码,遍历结果(索引和列)并为返回的每个索引调用GetCreateIndexScript。然后,您可以安全地执行为删除和重新创建索引而创建的每个语句。
这种方法可以与TSQL或其他语言一起使用。
答案 6 :(得分:0)
这是我想删除/创建/禁用/启用(重建)Microsoft SQL Server 索引的方法:
CREATE VIEW dbo.vw_INDEX_TEXT AS
SELECT
x.[owner_name],
x.[table_name],
x.[index_name],
/*
** DROP index
*/
drop_sql = 'DROP INDEX ' + x.[index_name] + ' ON ' + x.[owner_name] + '.' + x.[table_name] + ';',
/*
** CREATE index
*/
create_sql =
'CREATE NONCLUSTERED INDEX ' + x.[index_name] + '
ON ' + x.[owner_name] + '.' + x.[table_name] + '(' +
-- the common-delimited field list.
substring(
(SELECT
',' + [field_name]
FROM
(
SELECT
[owner_name] = SCHEMA_NAME(O.schema_id),
[table_name] = O.name,
[index_name] = I.name,
[field_name] = C.name,
O.type,
S.key_ordinal,
S.is_descending_key,
S.is_included_column
FROM
sys.all_objects O inner join sys.indexes I ON (O.object_id = I.object_id )
inner join sys.index_columns S ON (O.object_id = S.object_id and I.index_id=S.index_id)
inner join sys.columns C ON (O.object_id = C.object_id and S.column_id = C.column_id)
WHERE
I.index_id > 0
AND SCHEMA_NAME(O.schema_id) = x.[owner_name] -- N'dbo'
AND I.name = x.[index_name] -- the index name N'IDX_myindex'
AND O.name = x.[table_name] -- the base table name N'mytable'
AND O.type <> 'IT'
AND I.is_primary_key = 0 -- we are not creating primary keys
AND I.is_unique_constraint = 0 -- we are not creating unique constraints
AND (INDEXPROPERTY(I.object_id,I.name,'IsStatistics') <> 1)
AND (INDEXPROPERTY(I.object_id,I.name,'IsAutoStatistics') <> 1)
AND (INDEXPROPERTY(I.object_id,I.name,'IsHypothetical') <> 1)
) as f
FOR XML PATH('')
), 2, 8000) -- we trim the leading comma
-- end of field list
+ ')
WITH (
PAD_INDEX = OFF
);',
/*
** DISABLE index
*/
disable_sql = 'ALTER INDEX ' + x.[index_name] + ' ON ' + x.[owner_name] + '.' + x.[table_name] + ' DISABLE;',
/*
** ENABLE (REBUILD) index
*/
enable_sql = 'ALTER INDEX ' + x.[index_name] + ' ON ' + x.[owner_name] + '.' + x.[table_name] + ' REBUILD;'
FROM
(SELECT
[owner_name] = SCHEMA_NAME(O.schema_id),
[table_name] = O.name,
[index_name] = I.name
-- other interesting, but not used fields that might be useful for other index types:
-- O.type,I.index_id,I.is_unique,
-- prop= INDEXPROPERTY(I.object_id,I.name,'IsClustered'),
-- I.is_padded,
-- I.fill_factor,
-- I.ignore_dup_key,I.allow_row_locks,I.allow_page_locks,I.is_disabled,I.data_space_id
FROM
sys.all_objects O INNER JOIN sys.indexes I on O.object_id=I.object_id
WHERE
I.index_id>0
-- AND O.name = @target_table_name
AND O.type <> 'IT'
AND INDEXPROPERTY(I.object_id,I.name,'IsStatistics') <> 1
AND INDEXPROPERTY(I.object_id,I.name,'IsAutoStatistics') <> 1
AND INDEXPROPERTY(I.object_id,I.name,'IsHypothetical') <> 1
AND I.is_primary_key = 0
AND I.is_unique_constraint = 0
) as x
只重新创建了最基本的索引,但我留下了一些额外的字段,这些字段可用作根据需要创建更复杂索引的基础。
命令位于视图的每个字段中。使用 exec 实际执行这样的操作(输入 @target_table_name
的表名):
Declare @target_table_name as sysname = 'mytable';
Declare @sql_cmd as table(ID int identity, cmd varchar(max) );
Declare @this_cmd as varchar(max) = '';
Declare @ct as int = 0;
-- populate a temp table to store the results
INSERT INTO @sql_cmd(cmd)
SELECT
cmd = enable_sql
FROM
dbo.vw_INDEX_TEXT
WHERE
table_name = @target_table_name
-- the ID column will help us step though the rows one at a time
SELECT @ct = max(ID) FROM @sql_cmd
-- loop over all rows in the table, finding each individual command
While (@ct > 0) Begin
SELECT
@this_cmd = cmd
FROM
@sql_cmd
WHERE
id = @ct
select @this_cmd
-- un-comment this line to actually run the command:
-- exec (@this_cmd)
SET @ct = @ct - 1
End
请注意,示例中禁用了 exec
。