Como eu estava juntando alguns conjuntos de dados de teste, notei um comportamento engraçado com tabelas temporárias. Ao trabalhar com grandes conjuntos de dados em tabelas temporárias clusterizadas que são preenchidas por meio de um plano de execução paralela, a chave clusterizada não parece ser respeitada ao selecionar os dados. Esse problema também parece afetar todas as versões do SQL Server que testei (incluindo vNext).
Aqui está um exemplo dbfiddle.uk do teste. Você pode ter que executá-lo algumas vezes para obter o resultado que estou encontrando, mas não deve demorar mais de uma ou duas execuções para produzir os mesmos resultados. Além disso, este é o plano de execução local que estou obtendo no meu ambiente, que mostra que a única diferença entre os conjuntos de dados grandes e pequenos é a maneira como os dados são alimentados nas tabelas (por exemplo, plano paralelo versus serial).
Se você quiser jogar em casa, aqui está o teste que estou executando:
-- Large Data Set
CREATE TABLE #tmp
(
ID INT PRIMARY KEY CLUSTERED
)
INSERT INTO #tmp
-- Purposely insert in reverse order
SELECT TOP 100 PERCENT RN
FROM
(
SELECT TOP (10000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) x
ORDER BY RN DESC
-- Smaller Data Set
CREATE TABLE #tmp2
(
ID INT PRIMARY KEY CLUSTERED
)
INSERT INTO #tmp2
-- Purposely insert in reverse order
SELECT TOP 100 PERCENT RN
FROM
(
SELECT TOP (10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) x
ORDER BY RN DESC
-- Large Record Set
-- Clustered Key Not Honored*
SELECT TOP 10 *
FROM #tmp
-- Small Record Set
-- Clustered Key Honored
SELECT TOP 10 *
FROM #tmp2
DROP TABLE #tmp
DROP TABLE #tmp2
Não encontrei nenhuma referência indicando que esse é o comportamento esperado, mas antes de enviar um item de conexão , primeiro queria entrar em contato e confirmar que esse não é um problema localizado. Alguém pode me indicar a documentação que identifica esse comportamento esperado ou, alternativamente, confirmar que isso é, de fato, um bug?
EDIT: Em resposta aos comentários sobre a não inclusão de uma ORDER BY
cláusula, eu sempre supunha que a palavra-chave TOP retornasse os dados na ordem em que foram inseridos, que deveria , neste caso, ser a ordem ditada pela chave clusterizada. Ao executar a mesma instrução em uma tabela formal, o comportamento esperado é retornado:
-- Large Data Set with a Formal Data Table
CREATE TABLE tmp
(
ID INT PRIMARY KEY CLUSTERED
)
INSERT INTO tmp
-- Purposely insert in reverse order
SELECT TOP 100 PERCENT RN
FROM
(
SELECT TOP (10000000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM master..spt_values t1
CROSS JOIN master..spt_values t2
) x
ORDER BY RN DESC
-- Large Record Set
-- Clustered Key Not Honored*
SELECT TOP 10 *
FROM tmp
DROP TABLE tmp
(6325225 row(s) affected)
(1 row(s) affected)
ID
-----------
1
2
3
4
5
6
7
8
9
10
(10 row(s) affected)
(1 row(s) affected)
Até os planos de execução são os mesmos, então por que os diferentes conjuntos de resultados entre uma tabela temporária e uma tabela formalmente definida?
Finalmente, um salve para Joe Obbish enquanto eu roubei gratuitamente sua abordagem CROSS JOIN para construir grandes conjuntos de dados de teste, pois é bastante eficiente!
Não há garantia de
ORDER
semORDER BY
.O plano de execução para ambos tem "Ordered = False".
Isso significa que você pode obter os resultados em ordem de chave, mas também não.
Consulte especificamente Quando as varreduras de ordem de alocação podem ser usadas?
Como a tabela temporária local não é acessível a outras conexões, você obtém esse comportamento sem explicitamente usar um bloqueio de tabela, no entanto, o comentário sobre o tamanho da tabela ainda se aplica, e é por isso que você vê a diferença nos dois casos.
Se você precisar de um pedido específico, adicione um
ORDER BY
para obter a digitalização em ordem de chave (com"Ordered = True"
).Da Microsoft - em relação ao Topo
Para obter qualquer tipo de pedido, você precisa usar a cláusula order by .
Portanto, não importa quais chaves primárias, índices ou qualquer outra coisa que você faça na tabela, a única maneira de obter qualquer tipo de ordem, sem o N superior, é usar a cláusula order by.