Como otimizar uma consulta para que ela procure primeiro um índice e depois outro índice depois disso

12

Eu tenho dois conjuntos de medições da Terra a partir de dados de satélite, cada um com campos de tempo (mjd para data média juliana) e posições geográficas (GeoPoint, espacial) e estou procurando coincidências entre os dois conjuntos, para que seus horários correspondam a um limite de 3hrs (ou 0,125 dias) e suas distâncias até 200 km um do outro.

Fiz índices para os campos mjd nas tabelas e nas tabelas espaciais.

Quando eu entrei na restrição de tempo, o banco de dados calcula 100.000 correspondências em 8 segundos e calcula as distâncias para todas as 100.000 correspondências nesse período. A consulta fica assim:

select top 100000 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
option( table hint ( h, index(ix_MJD) ), table hint( m, index(ix_MJD) ) )

E o plano executado é:

Somente restrição mjd

Quando ordenadas, 9 das distâncias estavam abaixo de 200 km, portanto há partidas. O problema é que, quando adiciono a restrição de distância e corro isso,

select top 10 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
and h.GeoPoint.STDistance(m.GeoPoint)<200000
option( table hint ( h, index(ix_MJD) ), table hint( m, index(ix_MJD) ) )

desaparece por um longo tempo. Obviamente, em 8 segundos, ele poderia encontrar 100.000 combinações de tempo, 9 das quais com menos de 200 km, portanto o otimizador deve estar tentando algo sub-ideal. O plano é semelhante ao acima com um filtro nas distâncias (eu acho).

com constrangimento espacial, sem filtro espacial

Eu posso forçar o uso do índice espacial com isso:

select top 5 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0 
from L2V5.dbo.header h join L2.dbo.MLS_Header m 
on h.GeoPoint.STDistance(m.GeoPoint)<200000
and h.mjd between m.mjd-.125 and m.mjd+.125 
option( table hint ( h, index(ix_MJD), index(ix_GeoPoint) ), table hint( m, index(ix_MJD) ) )

ambas as restrições com ambos os índices

que leva 3 minutos para encontrar 5 correspondências.

Como digo ao otimizador de consulta para usar primeiro o índice MJD, e depois o índice espacial segundo (ou já é o que está fazendo)? Existe alguma maneira de ajudá-lo dizendo quantas correspondências esperar? Se ele puder calcular 100.000 correspondências com distâncias em 8 segundos, com 9 abaixo de 200 km, a adição do índice espacial não deve torná-lo mais rápido e mais lento?

Obrigado por outras dicas ou idéias.

EDIT: Para responder à pergunta como é o plano sem as dicas, isso (e leva uma eternidade):

sem dicas

Talvez também seja necessário mencionar que existem quase 1 milhão de registros em uma tabela e 8 milhões na outra

user261963
fonte
Como é o seu plano de consulta se você remover essas dicas?
Zane
@ Zane, editei a postagem e adicionei o plano de consulta sem sugestões. Ele substitui as buscas por varreduras e o tempo é péssimo.
User261963 6/15

Respostas:

6

O problema é que ele pode (e conhecendo os índices espaciais, provavelmente assumirá) que o filtro espacial seja muito mais seletivo que o filtro de tempo.

Mas se você tiver alguns milhões de registros em 200 km, poderá ser significativamente pior.

Você está pedindo para encontrar registros dentro de 200 km, que retornam dados ordenados por alguma ordem espacial. Encontrar os registros que estão próximos no tempo significa verificar cada um deles.

Ou então, você está encontrando registros por tempo e obtendo resultados na ordem do tempo. Em seguida, filtrar essa lista para o raio de 200 km é uma questão de verificar cada uma delas.

Se você filtrar os dados em dois intervalos como este, fica difícil aplicar o segundo filtro usando um índice. Talvez seja melhor dizer a ele para não usar o índice espacial se o filtro de tempo for o mais apertado.

Se ambos são grandes individualmente, e apenas juntos eles são estreitos, então você tem um problema mais complexo, que as pessoas tentam resolver há muito tempo e que pode ser bem resolvido por índices que cobrem 3D (e além) espaço. Exceto que o SQL Server não os possui.

Desculpe.

Editar: mais informações ...

Esse é um problema semelhante ao encontrar intervalos de tempo que abrangem um momento específico. Ao procurar os registros que começam antes desse ponto, você tem uma bagunça não ordenada do fim dos tempos - e vice-versa. Se você procurar pessoas na lista telefônica cujos sobrenomes começam com F, não poderá encontrar as pessoas cujos nomes começam com R com muita facilidade. E um índice no primeiro nome também não ajuda pelo mesmo motivo. Encontrar coisas no próximo índice é difícil quando o seu primeiro índice não é uma igualdade.

Agora, se você pudesse mudar seu filtro de data para um filtro de igualdade (ou uma série de filtros de igualdade), poderia ter uma chance, exceto que um índice espacial é um tipo especial de índice e não pode ser usado como o segundo nível em um índice composto.

Então você ficou com uma situação embaraçosa, receio. :(

Editar: Tente:

select top 100000 h.Time, m.Time, h.GeoPoint.STDistance(m.GeoPoint)/1000.0
from L2V5.dbo.header h join L2.dbo.MLS_Header m
on h.mjd between m.mjd-.125 and m.mjd+.125
where h.GeoPoint.STDistance(m.GeoPoint)/1000.0 < 200
option( table hint ( h, index(ix_MJD) ) );

Observe que estou deliberadamente quebrando a sargabilidade dividindo por 1000 antes de comparar com 200. Quero que este trabalho seja feito na Pesquisa de Chaves.

Lembre-se, você pode evitar a necessidade de pesquisas (e dicas) INCLUINDO o GeoPoint e o Time nos dois índices ix_MJD. Isso certamente tirará parte do calor do plano de consulta.

Rob Farley
fonte
Não sei se isso muda alguma coisa, mas o filtro de tempo é muito mais seletivo.
User261963
Está bem. Portanto, é aceitável localizar todas as linhas correspondentes ao tempo e verificar cada local sem o índice?
Rob Farley
... então o plano se parece com o original, mas tem um predicado ou filtro extra.
Rob Farley
Sugeriu algumas alterações com uma edição rápida. Você não precisa dar dicas sobre m, apenas h. Embora se você possa trocar para qual você está adicionando 1/8, certifique-se de modificar a coluna da tabela menor e usar esses valores para procurar a maior, isso também ajudará. Se h for 8M e m for 1M, deixe o predicado BETWEEN e insira apenas h. Se for o contrário, mude seu predicado e dica (mas melhor do que mudar a dica é adicionar essas colunas ao seu índice).
Rob Farley
Tirar todas as dicas da tabela parece funcionar melhor no final, desde que eu faça h entre me não o contrário. A consulta não usa mais os índices do GeoPoint, mas não os estava usando com eficiência. Incluí a coluna GeoPoint no índice MJD e isso ajudou muito. select top 10000 h.Time, m.Time, m.GeoPoint.STDistance(h.GeoPoint), h.mjd-m.mjd from L2V5.dbo.header h join L2.dbo.MLS_Header m on m.GeoPoint.STDistance(h.GeoPoint)<200000 and m.mjd between h.mjd-.125 and h.mjd+.125 order by h.mjd
User261963