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 / 237217
Accepted
Michael B
Michael B
Asked: 2019-05-03 06:13:46 +0800 CST2019-05-03 06:13:46 +0800 CST 2019-05-03 06:13:46 +0800 CST

Por que essa tabela derivada melhora o desempenho?

  • 772

Eu tenho uma consulta que leva uma string json como parâmetro. O json é uma matriz de pares de latitude e longitude. Um exemplo de entrada pode ser o seguinte.

declare @json nvarchar(max)= N'[[40.7592024,-73.9771259],[40.7126492,-74.0120867]
,[41.8662374,-87.6908788],[37.784873,-122.4056546]]';

Ele chama um TVF que calcula o número de POIs em torno de um ponto geográfico, a distâncias de 1,3,5,10 milhas.

create or alter function [dbo].[fn_poi_in_dist](@geo geography)
returns table
with schemabinding as
return 
select count_1  = sum(iif(LatLong.STDistance(@geo) <= 1609.344e * 1,1,0e))
      ,count_3  = sum(iif(LatLong.STDistance(@geo) <= 1609.344e * 3,1,0e))
      ,count_5  = sum(iif(LatLong.STDistance(@geo) <= 1609.344e * 5,1,0e))
      ,count_10 = count(*)
from dbo.point_of_interest
where LatLong.STDistance(@geo) <= 1609.344e * 10

A intenção da consulta json é chamar essa função em massa. Se eu chamar assim o desempenho é muito ruim levando quase 10 segundos para apenas 4 pontos:

select row=[key]
      ,count_1
      ,count_3
      ,count_5
      ,count_10
from openjson(@json)
cross apply dbo.fn_poi_in_dist(
            geography::Point(
                convert(float,json_value(value,'$[0]'))
               ,convert(float,json_value(value,'$[1]'))
               ,4326))

plano = https://www.brentozar.com/pastetheplan/?id=HJDCYd_o4

No entanto, mover a construção da geografia dentro de uma tabela derivada faz com que o desempenho melhore drasticamente, concluindo a consulta em cerca de 1 segundo.

select row=[key]
      ,count_1
      ,count_3
      ,count_5
      ,count_10
from (
select [key]
      ,geo = geography::Point(
                convert(float,json_value(value,'$[0]'))
               ,convert(float,json_value(value,'$[1]'))
               ,4326)
from openjson(@json)
) a
cross apply dbo.fn_poi_in_dist(geo)

plano = https://www.brentozar.com/pastetheplan/?id=HkSS5_OoE

Os planos parecem praticamente idênticos. Nenhum usa paralelismo e ambos usam o índice espacial. Há um carretel preguiçoso adicional no plano lento que posso eliminar com a dica option(no_performance_spool). Mas o desempenho da consulta não muda. Ainda continua muito mais lento.

A execução de ambos com a dica adicionada em um lote pesará as duas consultas igualmente.

Versão do servidor SQL = Microsoft SQL Server 2016 (SP1-CU7-GDR) (KB4057119) - 13.0.4466.4 (X64)

Então minha pergunta é por que isso importa? Como posso saber quando devo calcular valores dentro de uma tabela derivada ou não?

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

1 respostas

  • Voted
  1. Best Answer
    Martin Smith
    2019-05-03T08:07:35+08:002019-05-03T08:07:35+08:00

    Posso dar uma resposta parcial que explica por que você está vendo a diferença de desempenho - embora isso ainda deixe algumas questões em aberto (como o SQL Server pode produzir o plano mais ideal sem introduzir uma expressão de tabela intermediária que projeta a expressão como uma coluna?)


    A diferença é que no plano rápido o trabalho necessário para analisar os elementos da matriz JSON e criar a Geografia é feito 4 vezes (uma vez para cada linha emitida pela openjsonfunção) - enquanto é feito mais de 100.000 vezes no plano lento.

    No plano rápido...

    geography::Point(
                    convert(float,json_value(value,'$[0]'))
                   ,convert(float,json_value(value,'$[1]'))
                   ,4326)
    

    É atribuído Expr1000no escalar de computação à esquerda da openjsonfunção. Isso corresponde a geosua definição de tabela derivada.

    insira a descrição da imagem aqui

    No plano rápido, o filtro e a referência agregada de fluxo Expr1000. No plano lento, eles fazem referência à expressão subjacente completa.

    Propriedades agregadas de stream

    insira a descrição da imagem aqui

    O filtro é executado 116.995 vezes com cada execução exigindo uma avaliação de expressão. A agregação de fluxo tem 110.520 linhas fluindo para ela para agregação e cria três agregações separadas usando essa expressão. 110,520 * 3 + 116,995 = 448,555. Mesmo que cada avaliação individual leve 18 microssegundos, isso adiciona até 8 segundos de tempo adicional para a consulta como um todo.

    Você pode ver o efeito disso nas estatísticas de tempo real no XML do plano (anotado em vermelho abaixo do plano lento e azul para o plano rápido - os tempos estão em ms)

    insira a descrição da imagem aqui

    A agregação de fluxo tem um tempo decorrido 6,209 segundos maior que seu filho imediato. E a maior parte do tempo da criança foi ocupada pelo filtro. Isso corresponde às avaliações de expressão extra.


    A propósito.... Em geral, não é certo que expressões subjacentes com rótulos como Expr1000sejam calculadas apenas uma vez e não reavaliadas, mas claramente, neste caso, pela discrepância de tempo de execução, isso acontece aqui.

    • 15

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