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 / 330027
Accepted
Fajela Tajkiya
Fajela Tajkiya
Asked: 2023-08-08 00:50:19 +0800 CST2023-08-08 00:50:19 +0800 CST 2023-08-08 00:50:19 +0800 CST

Otimizando a consulta do SQL Server ao unir tabelas na coluna DATETIME

  • 772

Estou trabalhando com SQL Server e tenho duas tabelas, table1e table2. Ambas as tabelas têm uma DATETIMEcoluna indicada como dt. Preciso unir essas tabelas com base não apenas em certas condições, mas também para garantir que as linhas correspondentes tenham a mesma data (a hora não é considerada aqui) da dtcoluna.

Aqui está a consulta que estou usando atualmente:

select *
From table1 a inner join table2 b
    on a.id = b.a_id
    and convert(date, a.dt) = convert(date, b.dt)

Essa consulta funciona para obter os resultados de que preciso, mas estou preocupado com seu desempenho, especialmente à medida que as tabelas aumentam de tamanho.

Eu estou querendo saber se existem maneiras mais eficazes para alcançar o mesmo resultado? Existem técnicas ou recursos do SQL Server que possam me ajudar a otimizar essa consulta, principalmente a parte de comparação de datas?

Qualquer conselho ou sugestão seria muito apreciada. Agradeço antecipadamente.

sql-server
  • 5 5 respostas
  • 944 Views

5 respostas

  • Voted
  1. Best Answer
    Erik Darling
    2023-08-08T21:45:16+08:002023-08-08T21:45:16+08:00

    computando

    Se eu fosse você e tivesse que fazer isso repetidamente, provavelmente adicionaria colunas computadas que fornecem os tipos de dados desejados e as indexaria de acordo.

    ALTER TABLE table1 ADD dt_c AS CONVERT(date, dt);
    ALTER TABLE table2 ADD dt_c AS CONVERT(date, dt);
    

    Obviamente, isso não oferece nenhum benefício real por si só até que as colunas sejam indexadas para suportar a junção.

    O bom dessa abordagem é que adicionar as colunas computadas como não persistentes é uma operação rápida e sem bloqueio com quase zero de gravações no banco de dados. Você pode adiar isso para quando adicionar índices (que você precisa de qualquer maneira).

    E por meio da parte de correspondência de expressão da otimização de consulta, você nem precisa alterar a consulta original para o SQL Server usar as novas colunas.

    • 7
  2. Charlieface
    2023-08-08T00:54:47+08:002023-08-08T00:54:47+08:00

    Você pode usar um intervalo de datas em uma ou outra tabela

    select *
    From table1 a
    inner join table2 b
        on a.id = b.a_id
        and a.dt >= convert(datetime, convert(date, b.dt))
        and a.dt < dateadd(day, 1, convert(datetime, convert(date, b.dt)))
    

    Qualquer tabela que você escolher para usar as funções não pode usar índices, então escolha sabiamente. Teste os dois lados e examine o plano de execução.

    No SQL Server 2022 e no Azure SQL, você pode usar DATETRUNC(day, b.dt).

    • 4
  3. Martin Smith
    2023-08-08T01:16:08+08:002023-08-08T01:16:08+08:00

    Depende...

    Se você deseja um loop aninhado com uma busca de índice correlacionada e possui um índice adequado em pelo menos uma das tabelas com colunas iniciais, a id,dtconversão em uma busca de intervalo será o ideal, como na resposta de Charlie .

    Se você deseja uma junção de hash (talvez não tenha índices úteis), então

    a.id = b.a_id  and convert(date, a.dt) = convert(date, b.dt)
    

    ou

    a.id = b.a_id and DATETRUNC(day, b.dt) = DATETRUNC(day, a.dt)
    

    Pelo menos fornece um predicado de igualdade em ambas as condições, o que significa que ambas podem ser usadas na chave de hash.

    DATETRUNCé mais capaz de tirar proveito do fato de que um índice ordenado por datetimetambém é ordenado pordate e também permite uma junção de mesclagem com um predicado id, DATETRUNC(day, dt)sem nenhum operador de classificação se ambas as tabelas tiverem um índice ativado id, dt- embora isso seja um "muitos para muitos " digite com uma mesa de trabalho.

    StmtText
      |--Merge Join(Inner Join, MANY-TO-MANY MERGE:([a].[id], [Expr1003])=([b].[a_id], [Expr1002]), RESIDUAL:([dbo].[table1].[id] as [a].[id]=[dbo].[table2].[a_id] as [b].[a_id] AND [Expr1002]=[Expr1003]))
           |--Compute Scalar(DEFINE:([Expr1003]=datetrunc(day,[dbo].[table1].[dt] as [a].[dt])))
           |    |--Clustered Index Scan(OBJECT:([dbo].[table1].[PK__table1__D132DEDA9CF69990] AS [a]), ORDERED FORWARD)
           |--Compute Scalar(DEFINE:([Expr1002]=datetrunc(day,[dbo].[table2].[dt] as [b].[dt])))
                |--Clustered Index Scan(OBJECT:([dbo].[table2].[PK__table2__B54BCC7FCA4E9E10] AS [b]), ORDERED FORWARD)
    

    A convert(date, a.dt)opção também ofereceria suporte a uma pesquisa indexada com loops aninhados e uma igualdade ide busca de intervalo dt, embora não tão eficiente quanto construir o intervalo por conta própria, pois a busca dinâmica lê um dia adicional.

      |--Nested Loops(Inner Join, OUTER REFERENCES:([a].[id], [Expr1002]))
           |--Compute Scalar(DEFINE:([Expr1002]=CONVERT(date,[dbo].[table1].[dt] as [a].[dt],0)))
           |    |--Clustered Index Scan(OBJECT:([dbo].[table1].[PK__table1__D132DEDA9CF69990] AS [a]))
           |--Nested Loops(Inner Join, OUTER REFERENCES:([Expr1005], [Expr1006], [Expr1004]))
                |--Compute Scalar(DEFINE:(([Expr1005],[Expr1006],[Expr1004])=GetRangeThroughConvert([Expr1002],[Expr1002],(62))))
                |    |--Constant Scan
                |--Clustered Index Seek(OBJECT:([dbo].[table2].[PK__table2__B54BCC7FCA4E9E10] AS [b]), SEEK:([b].[a_id]=[dbo].[table1].[id] as [a].[id] AND [b].[dt] > [Expr1005] AND [b].[dt] < [Expr1006]),  WHERE:([Expr1002]=CONVERT(date,[dbo].[table2].[dt] as [b].[dt],0)) ORDERED FORWARD)
    

    A lógica de busca dinâmica não se estende a DATETRUNCisso, então o melhor que se pode fazer com loops aninhados é uma igualdade na idparte e residual na data.

       |--Nested Loops(Inner Join, OUTER REFERENCES:([a].[id], [Expr1003]))
           |--Compute Scalar(DEFINE:([Expr1003]=datetrunc(day,[dbo].[table1].[dt] as [a].[dt])))
           |    |--Clustered Index Scan(OBJECT:([dbo].[table1].[PK__table1__D132DEDA9CF69990] AS [a]))
           |--Clustered Index Seek(OBJECT:([dbo].[table2].[PK__table2__B54BCC7FCA4E9E10] AS [b]), SEEK:([b].[a_id]=[dbo].[table1].[id] as [a].[id]),  WHERE:(datetrunc(day,[dbo].[table2].[dt] as [b].[dt])=[Expr1003]) ORDERED FORWARD)
    
    • 4
  4. J.D.
    2023-08-08T03:51:50+08:002023-08-08T03:51:50+08:00

    Dependendo de quanto as tabelas subjacentes são gravadas versus com que frequência elas são lidas com essa consulta, outra opção que você pode considerar é uma exibição indexada .

    Uma exibição indexada persistirá os resultados da consulta como se fosse uma tabela em si. Essa compensação de uso de espaço em disco adicional e sobrecarga de gravação beneficia o desempenho de leitura aprimorado - essencialmente como se a consulta estivesse lendo diretamente de uma tabela.

    Geralmente, existem algumas limitações de exibições indexadas , mas sua consulta parece se adequar aos critérios que a tornam utilizável para ela. Você pode criar um assim:

    Primeiro ceite a visão com a SCHEMABINDINGopção (listando explicitamente as colunas e chamando seus nomes de esquema, conforme os requisitos):

    CREATE VIEW dbo.SomeIndexedView
    WITH SCHEMABINDING
    AS
    
    select a.id, a.dt, b.Column1, b.Column2 -- etc
    From dbo.table1 a inner join dbo.table2 b
        on a.id = b.a_id
        and convert(date, a.dt) = convert(date, b.dt);
    

    Em seguida, crie um índice clusterizado exclusivo na exibição recém-criada para convertê-lo em uma exibição indexada que persiste no disco:

    CREATE UNIQUE CLUSTERED INDEX IX_SomeIndexedView_Key ON dbo.SomeIndexedView (id, dt);
    

    Por fim, selecione na exibição indexada recém-criada com a NOEXPANDdica para garantir que ela use a cópia persistente dos dados:

    SELECT * -- In general, you shouldn't really use SELECT *, instead explicitly list out your columns
    FROM dbo.SomeIndexedView WITH (NOEXPAND);
    

    As exibições indexadas também são úteis se você não tiver controle para modificar os índices das próprias tabelas subjacentes.

    • 3
  5. Otto
    2023-08-08T19:49:00+08:002023-08-08T19:49:00+08:00

    A solução mais rápida seria adicionar uma coluna de data extra a ambas as tabelas e garantir que ela seja preenchida por qualquer programa que esteja gravando nas tabelas. Atualize os dados existentes com:

    update table1 
    set [date] = convert(date, a.dt) 
    

    Então a consulta existente seria:

    select *
    From table1 a inner join table2 b
        on a.id = b.a_id
        and a.[date] = b.[date] 
    
    • -2

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