Estou enfrentando um problema de longa data em que o SSDT pensará que um índice de tabela no meu banco de dados SQL do Azure não existe, quando na verdade existe.
Após as últimas horas pesquisando os rastreamentos do XEvent e percorrendo a desmontagem do SSDT, descobri que o motivo é porque o SSDT procura índices com essa consulta (repetida abaixo para googleabilidade).
A consulta tem o predicado [i].[auto_created] = 0
.
Quero manter o índice em vez de recriá-lo - existe alguma maneira de definir sys.indexes.auto_created = 0
um índice específico de alguma forma?
ATUALIZAÇÃO: Acabei de encontrar este tópico, parece que não estou sozinho , mas também não devo esperar nenhuma alteração no SSDT, * grumble *
UPDATE2: Curiosamente, usar WITH AUTO_CREATED = ON
é uma opção válida para o CREATE INDEX
SQL do Azure , mas não para ALTER INDEX
, *mais resmungando* : quando tentei, recebi este erro:
ALTER INDEX IX_StarTrekTngBestMoments ON dbo.GeneRoddenberryFanClub SET ( AUTO_CREATED = OFF );
Msg 155, Nível 15, Estado 1, Linha 1
'AUTO_CREATED' não é uma opção ALTER INDEX reconhecida.
História para os curiosos:
- Cerca de 2-3 anos atrás, o Azure SQL Performance Analyzer criou automaticamente um índice em uma das minhas tabelas.
- O tipo de índices com um nome como
nci_wi_TableName_ABCDEF...
.
- O tipo de índices com um nome como
- Quando o Azure SQL Performance Analyzer cria um índice, exibição ou outro objeto, ele define o
auto_created
sinalizador como1
. - As ferramentas de design do SQL Server do Visual Studio (SSDT, também conhecido como
*.sqlproj
) sempre excluem objetos comauto_created <> 0
, o que significa que o SSDT não viu meu índice. - Você pensaria que isso não seria um problema porque o índice não estava no meu projeto em primeiro lugar, então não há conflito, certo?
- Bem, não - na época eu usei SSMS, não SSDT, para copiar a
INDEX
definição de 's no meu projeto SSDT - usando o menu "Script index as CREATE to..." e copiando + colando o SQL no meu arquivo de tabela SSDT . E desde então tenho tido conflitos com SSDT versus meu banco de dados SQL do Azure - sem ter problemas com minhas versões de desenvolvimento local e local porque o SSDT as criou sem oauto_created
sinalizador.
- Bem, não - na época eu usei SSMS, não SSDT, para copiar a
- Enviei um tíquete de suporte ao suporte do Azure sobre isso em janeiro de 2021 - a solicitação de suporte foi muito lenta, mas em março de 2021 eles me disseram que "enviarão o plano de ação em breve" (o que quer que isso signifique), mas eu não ouvi qualquer coisa desde... Vergonha , Microsoft, Vergonha .
Eu esperava que houvesse uma opção no SSDT para não ignorar auto_created
objetos, mas infelizmente a consulta SQL que ele usa para enumerar índices no banco de dados tem o termo predicado codificado:
SELECT * FROM (
SELECT * FROM (
SELECT DISTINCT
SCHEMA_NAME([o].[schema_id]) AS [SchemaName]
,[i].[object_id] AS [ColumnSourceId]
,[o].[name] AS [ColumnSourceName]
,[o].[type] AS [ColumnSourceType]
,[i].[index_id] AS [IndexId]
,[i].[name] AS [IndexName]
,[f].[type] AS [DataspaceType]
,[f].[data_space_id] AS [DataspaceId]
,[f].[name] AS [DataspaceName]
,CASE WHEN exists(SELECT 1 FROM [sys].[columns] AS [c] WITH (NOLOCK) WHERE [c].[object_id] = [o].[object_id] AND [c].[is_filestream] = 1) THEN
[ds].[data_space_id]
ELSE
NULL
END AS [FileStreamId]
,[ds].[name] AS [FileStreamName]
,[ds].[type] AS [FileStreamType]
,[i].[fill_factor] AS [FillFactor]
,CONVERT(bit, CASE [i].[type] WHEN 1 THEN 1 WHEN 5 THEN 1 ELSE 0 END)
AS [IsClustered]
,[i].[is_unique] AS [IsUnique]
,[i].[is_padded] AS [IsPadded]
,[i].[ignore_dup_key] AS [DoIgnoreDuplicateKey]
,[t].[no_recompute] AS [NoRecomputeStatistics]
,[t].[is_incremental] AS [DoIncrementalStatistics]
,[i].[allow_row_locks] AS [DoAllowRowLocks]
,[i].[allow_page_locks] AS [DoAllowPageLocks]
,[i].[is_disabled] AS [IsDisabled]
,[i].[filter_definition]
AS [Predicate]
,[i].[compression_delay] AS [CompressionDelay]
,CONVERT(bit, ISNULL(INDEXPROPERTY([i].[object_id], [i].[name], N'IsOptimizedForSequentialKey'), 0)) AS [DoOptimizeForSequentialKey]
,CONVERT(bit, CASE WHEN [ti].[data_space_id] <> [i].[data_space_id] THEN 0 ELSE 1 END)
AS [EqualsParentDataSpace]
,[i].[type] AS [IndexType]
,[i].[auto_created] AS [AutoCreated]
,CONVERT(BIT, CASE WHEN [hi].[object_id] IS NULL THEN 0 ELSE 1 END) AS [IsHash]
,[hi].[bucket_count] AS [BucketCount]
FROM
[sys].[indexes] AS [i] WITH (NOLOCK)
INNER JOIN [sys].[objects] AS [o] WITH (NOLOCK) ON [i].[object_id] = [o].[object_id]
LEFT JOIN [sys].[data_spaces] AS [f] WITH (NOLOCK) ON [i].[data_space_id] = [f].[data_space_id]
LEFT JOIN [sys].[stats] AS [t] WITH (NOLOCK) ON [t].[object_id] = [i].[object_id] AND [t].[name] = [i].[name]
LEFT JOIN [sys].[tables] AS [ta] WITH (NOLOCK) ON [ta].[object_id] = [i].[object_id]
LEFT JOIN [sys].[data_spaces] AS [ds] WITH (NOLOCK) ON [ds].[data_space_id] = [ta].[filestream_data_space_id]
LEFT JOIN (SELECT * FROM [sys].[indexes] WITH (NOLOCK) WHERE [index_id] < 2) AS [ti] ON [o].[object_id] = [ti].[object_id]
LEFT OUTER JOIN [sys].[hash_indexes] AS [hi] WITH (NOLOCK) ON [hi].[object_id] = [i].[object_id] AND [hi].[index_id] = [i].[index_id]
WHERE
([o].[type] = N'U' OR [o].[type] = N'V')
AND [i].[is_primary_key] = 0
AND [i].[is_unique_constraint] = 0
AND [i].[is_hypothetical] = 0
AND [i].[name] IS NOT NULL
AND [i].[auto_created] = 0
AND ([o].[is_ms_shipped] = 0 AND NOT EXISTS (SELECT *
FROM [sys].[extended_properties]
WHERE [major_id] = [o].[object_id]
AND [minor_id] = 0
AND [class] = 1
AND [name] = N'microsoft_database_tools_support'
))) indexBase
WHERE [IndexType] NOT IN (3, 4, 5, 6)
) AS [_results] ORDER BY ColumnSourceId,IndexId OPTION (USE HINT('FORCE_LEGACY_CARDINALITY_ESTIMATION'));
Não é o ideal, mas você pode descartar e recriar o(s) índice(s). Obviamente, isso pode levar algum tempo se a tabela for grande, portanto, talvez seja necessário programá-la para um período de manutenção se for um aplicativo de produção. E se por algum motivo você quiser manter o sinalizador depois, precisará descartar e recriar novamente para redefini-lo.
Como sugerido por AMtwo nos comentários abaixo: você pode criar o índice de substituição primeiro , depois descartar aquele com o sinalizador e renomear o novo (renomear é importante se o índice original puder ser referido em qualquer dica de consulta). Isso ocupará mais espaço temporariamente, mas não deixará você com um ponto enquanto não houver índice cobrindo essas colunas, o que pode ser importante se você estiver trabalhando com um banco de dados ativo em vez de fazer isso em um período de manutenção.