AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 240584
Accepted
Michael B
Michael B
Asked: 2019-06-15 06:33:22 +0800 CST2019-06-15 06:33:22 +0800 CST 2019-06-15 06:33:22 +0800 CST

Como forço o SQL Server a usar meu índice espacial por meio de uma exibição?

  • 772

Eu tenho tabelas que contém transações para propriedades que são armazenadas como pares long long. (Existem mais colunas e pontos de dados do que no meu esquema de exemplo).

Uma solicitação comum é encontrar as transações que aconteceram a X milhas de um determinado ponto e recuperar apenas as 5 transações mais recentes que aconteceram para cada propriedade próxima.

Para fazer isso funcionar, decidi adicionar uma visão que encapsula essa lógica das mais recentes:

create or alter view dbo.v_example
with schemabinding as
select example_id
      ,transaction_dt
      ,latitude
      ,longitude
      ,latlong
      ,most_recent= iif(row_number() over (partition by latitude,longitude order by transaction_dt desc) < 5,1,null)
from dbo.example;

Portanto, uma consulta pode ser assim::

select *
from dbo.v_example
where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
and most_recent = 1

Infelizmente, o SQL Server não quer usar o índice espacial quando eu consulto pela view. Se eu remover schemabindinge tentar adicionar uma dica na exibição, recebo que o processador de consultas não pode criar um plano.

Como posso encapsular a lógica e ainda fazer com que ela use meu índice espacial?

Aqui está um db<>fiddle com dados de exemplo e formas de plano .

A tabela é muito maior e é muito mais lento varrê-la do que fazer uma busca de índice clusterizado e, em seguida, encontrar o ponto próximo.

sql-server sql-server-2016
  • 1 1 respostas
  • 437 Views

1 respostas

  • Voted
  1. Best Answer
    Randi Vertongen
    2019-06-15T08:58:04+08:002019-06-15T08:58:04+08:00

    Funções e visualizações da janela

    Recentemente, respondi a uma pergunta diferente sobre visualizações e funções da janela, mas nem todas as respostas dadas se aplicam aqui.

    Duas diferenças são que este exemplo usa geographytipos de dados e filtros na função de janela. A parte positiva aqui é que você não está vinculado à função window e pode usar algo como CROSS APPLYobter os resultados mais próximos para uma combinação de latitude& .longitude

    A pergunta anterior + resposta

    Em resumo , a função da janela é calculada antes da aplicação da filtragem.

    POR EXEMPLO

    where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
    and most_recent = 1
    

    Informações extras podem ser encontradas nesta postagem do blog de 2013 de Paul White sobre funções e visualizações da janela.

    Teste

    Como primeiro teste, o resultado é claro ao omitir o ROW_NUMBER()da visão

    create or alter view dbo.v_example2
    with schemabinding as
    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
    from dbo.example;
    
    set statistics xml on;
    select *
    from dbo.v_example2
    where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
    

    Resultando no plano de consulta de desempenho esperado.

    DB<>Fiddle


    Mas você obviamente ainda quer a filtragem adicional

    Mantendo a função view + window

    Você pode optar por adicionar a função de janela posteriormente, assim:

    create or alter view dbo.v_example2
    with schemabinding as
    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
    from dbo.example;
    

    &

    set statistics xml on;
    ;WITH CTE AS
    (
    select most_recent= iif(row_number() over (partition by latitude,longitude order by transaction_dt desc) < 5,1,null)
    ,*
    from dbo.v_example2
    where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
    )
    SELECT
    * 
    FROM CTE
    WHERE most_recent is not null;
    

    Novamente resultando no plano de execução esperado.

    DB<>Fiddle


    Usando uma função de valor de tabela em linha + função de janela

    CREATE FUNCTION dbo.F_Example
    (
        @P1 INT
    
    )  
    RETURNS TABLE
    WITH SCHEMABINDING AS
    RETURN
        (
    SELECT example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
          ,most_recent FROM
    (
    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
          ,most_recent= iif(row_number() over (partition by latitude,longitude order by transaction_dt desc) < 5,1,null)
    from dbo.example
    WHERE latlong.STDistance(geography::Point(40,-74,4326)) <= 1609.344e1
    ) AS A
    WHERE most_recent= @P1
    );
    
    EXEC SP_EXECUTESQL
    N'SELECT * FROM  dbo.F_Example(@P1)',N'@P1 INT',@P1 = 1
    

    Resultando no plano de consulta que você esperava.

    DB<>Fiddle

    Usando uma função CTE + janela

    ;WITH CTE AS
    (
    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
          ,most_recent= row_number() over (partition by latitude,longitude order by transaction_dt desc)
    FROM dbo.example
    WHERE latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
    )
    
    SELECT example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
          ,most_recent
    FROM CTE2
    WHERE most_recent < 5;
    

    Usando CROSS APPLYe TOP(4) sem a função de janela

    SELECT example_id
          ,a.transaction_dt
          ,latitude
          ,longitude
          ,latlong
    from dbo.example e1
    CROSS APPLY(
    SELECT TOP(4) transaction_dt
    FROM dbo.example e2
    WHERE e1.latitude = e2.latitude  and e1.longitude = e2.longitude
    GROUP BY latitude,longitude,transaction_dt
    ORDER BY transaction_dt desc
    ) as a
    WHERE latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
    AND e1.transaction_dt = a.transaction_dt
    ORDER BY transaction_dt desc;
    

    Eu usei top(4)desde que o conjunto de resultados foi baseado em < 5não<= 5

    Ao usar o CROSS APPLYmétodo, há mais um índice a ser adicionado, para remover o spool de índice e classificar:

    insira a descrição da imagem aqui

    CREATE INDEX IX_latitude_longitude_transaction_dt
    ON dbo.example(latitude,longitude,transaction_dt);
    

    insira a descrição da imagem aqui

    Escusado será dizer que você pode adicionar a CROSS APPLYsolução a uma visualização e consultá-la da mesma maneira que costumava fazer, um exemplo disso aqui . Todos os exemplos acima em um DB<>Fiddle aqui .


    Comentário da solução final de MichaelB

    Obrigado Randi, consegui reescrever minha lógica em uma subconsulta select usando a ideia de sua aplicação cruzada. Como um bônus adicional, se eu não mencionar o campo nas colunas que seleciono, não recebo um impacto no desempenho.

    DB<>Fiddle

    create or alter view dbo.v_example2
    with schemabinding as
    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
          ,most_recent= (
              select a.transaction_dt
              intersect
              select top 5 b.transaction_dt
              from dbo.example b
              where a.latitude=b.latitude
                    and a.longitude=b.longitude
              order by transaction_dt desc
          )
    from dbo.example a;
    

    &

    select example_id
          ,transaction_dt
          ,latitude
          ,longitude
          ,latlong
    from dbo.v_example2
    where latlong.STDistance(geography::Point(40,-74,4326)) <=1609.344e1
          and most_recent is not null
    
    • 5

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve