Estou armazenando dados do sensor em uma tabela SensorValues . A tabela e a chave primária são as seguintes:
CREATE TABLE [dbo].[SensorValues](
[DeviceId] [int] NOT NULL,
[SensorId] [int] NOT NULL,
[SensorValue] [int] NOT NULL,
[Date] [int] NOT NULL,
CONSTRAINT [PK_SensorValues] PRIMARY KEY CLUSTERED
(
[DeviceId] ASC,
[SensorId] ASC,
[Date] DESC
) WITH (
FILLFACTOR=75,
DATA_COMPRESSION = PAGE,
PAD_INDEX = OFF,
STATISTICS_NORECOMPUTE = OFF,
SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF,
ONLINE = OFF,
ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON)
ON [MyPartitioningScheme]([Date])
No entanto, quando seleciono o valor do sensor válido por um tempo específico, o plano de execução diz que está fazendo uma classificação. Por que é que?
Eu pensaria que, desde que eu armazene os valores classificados pela coluna Data, a classificação não ocorrerá. Ou é porque o índice não é classificado apenas pela coluna Data, ou seja, não pode assumir que o conjunto de resultados foi classificado?
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
ORDER BY Date DESC
Edit: Posso fazer isso?
Como a tabela é classificada DeviceId, SensorId, Date e eu fazemos um SELECT especificando apenas um DeviceId e um SensorId , o conjunto de saída já deve ser classificado por Data DESC . Então, eu me pergunto se a seguinte pergunta renderia o mesmo resultado em todos os casos?
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND Date < 1339225010
De acordo com @Catcall abaixo, a ordem de classificação não é a mesma que a ordem de armazenamento. Ou seja, não podemos assumir que os valores retornados já estejam em uma ordem classificada.
Edit: Eu tentei esta solução CROSS APPLY, sem sorte
@ Martin Smith sugeriu que eu tentaria aplicar o meu resultado fora das partições. Encontrei uma postagem no blog ( índices alinhados não agrupados na tabela particionada ) descrevendo esse problema semelhante e tentei a solução um pouco semelhante à sugerida por Smith. No entanto, sem sorte aqui, o tempo de execução está a par da minha solução original.
WITH Boundaries(boundary_id)
AS
(
SELECT boundary_id
FROM sys.partition_functions pf
JOIN sys.partition_range_values prf ON pf.function_id = prf.function_id
WHERE pf.name = 'PF'
AND prf.value <= 1339225010
UNION ALL
SELECT max(boundary_id) + 1
FROM sys.partition_functions pf
JOIN sys.partition_range_values prf ON pf.function_id = prf.function_id
WHERE pf.name = 'PF'
AND prf.value <= 1339225010
),
Top1(SensorValue)
AS
(
SELECT TOP 1 d.SensorValue
FROM Boundaries b
CROSS APPLY
(
SELECT TOP 1 SensorValue
FROM SensorValues
WHERE SensorId = 53
AND DeviceId = 3819
AND "Date" < 1339225010
AND $Partition.PF(Date) = b.boundary_id
ORDER BY Date DESC
) d
ORDER BY d.Date DESC
)
SELECT SensorValue
FROM Top1
Respostas:
Para uma tabela não particionada, recebo o seguinte plano
Existe um único predicado de busca ativado
Seek Keys[1]: Prefix: DeviceId, SensorId = (3819, 53), Start: Date < 1339225010
.Significa que o SQL Server pode executar uma busca de igualdade nas duas primeiras colunas e iniciar uma busca de intervalo iniciando
1339225010
e ordenadaFORWARD
(conforme o índice é definido[Date] DESC
)O
TOP
operador irá parar de solicitar mais linhas da busca após a primeira linha ser emitida.Quando eu crio o esquema e a função de partição
E preencha a tabela com os seguintes dados
O plano no SQL Server 2008 é o seguinte.
O número real de linhas emitidas a partir da pesquisa é
500
. O plano mostra procurar predicadosIndicando que está usando a abordagem de ignorar varredura descrita aqui
Esse plano é um plano serial e, portanto, para a consulta específica, parece que, se o SQL Server garantisse o processamento das partições em ordem decrescente,
date
o plano originalTOP
ainda funcionaria e poderia interromper o processamento após a primeira linha correspondente. encontrado em vez de continuar e gerar as 499 correspondências restantes.De fato, o plano para 2005 parece seguir essa abordagem
Eu não tenho certeza se ele é para a frente para obter o mesmo plano em 2008 ou talvez seria necessário um
OUTER APPLY
emsys.partition_range_values
simular isso.fonte
Muitas pessoas acreditam que um índice em cluster garante uma ordem de classificação na saída. Mas não é isso que faz; garante uma ordem de armazenamento em disco.
Veja, por exemplo, esta postagem no blog e essa discussão mais longa .
fonte
Estou especulando que o SORT é necessário por causa do plano paralelo. Baseei isso em algum artigo obscuro e distante do blog: mas encontrei isso no MSDN, o que pode ou não justificar isso
Então, tente com o MAXDOP 1 e veja o que acontece ...
Também sugerido na postagem do blog de @sql kiwi no Simple Talk, em "Exchange Operator", eu acho. E "dependência DOP" aqui
fonte
date
antes. Agora eu tenho e parece que particionar é o culpado de 2005 possivelmente se comportando melhor para essa consulta em particular.Basicamente, você está certo - já que a chave primária está na ordem "DeviceId, SensorId, Date", os dados na chave não são classificados por data, portanto, não podem ser usados. Se a sua chave estivesse em uma ordem diferente "Data, DeviceId, SensorId", os dados na chave seriam classificados por data, para que pudessem ser usados ...
fonte