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 / 4782
Accepted
Stuart Blackler
Stuart Blackler
Asked: 2011-08-19 11:24:52 +0800 CST2011-08-19 11:24:52 +0800 CST 2011-08-19 11:24:52 +0800 CST

Conselho com coluna de data SQL Server 2005

  • 772

Eu tenho duas colunas de data e hora no SQL Server 2005 que preciso consultar sem a parte de hora da data e hora. Atualmente, minha consulta se parece com isso (apenas um exemplo):

WITH Dates AS ( 
        SELECT [Date] = @StartDate
        UNION ALL SELECT [Date] = DATEADD(DAY, 1, [Date])
        FROM Dates WHERE [Date] < @EndDate
) 
SELECT DISTINCT ID
FROM table t
CROSS APPLY DATES d
WHERE d.[Date] BETWEEN CONVERT(DATETIME, CONVERT(VARCHAR, t.StartDate, 103)) AND CONVERT(DATETIME, CONVERT(VARCHAR, t.EndDate, 103))

Agora, isso resulta em uma varredura de índice clusterizada completa (surpresa, surpresa). Estou tentando pensar em maneiras de tornar isso mais rápido (a consulta real leva 3 minutos: O). Pensei em fazer o seguinte, mas ainda não tentei, pois fiquei sem tempo antes:

  1. Use uma coluna computada apenas com a parte da data
  2. Indexar a referida coluna computada (não tenho certeza se isso é possível?)
  3. Use uma exibição indexada (novamente, não tenho certeza se isso é possível, funcionará?)

A maneira mais fácil seria atualizar a coluna e remover todas as informações de tempo, mas não posso fazer isso :(

Alguma ideia?

Atualizar

Obrigado por todas as respostas até agora. Acho que o ponto da pergunta foi perdido porque não estava claro sobre o que queria. Foi mal. Eu pretendia apenas otimizar a parte de conversão de data da consulta, pois a quantidade de dados com a qual estou lidando é pequena na realidade (< 500.000 após a aplicação cruzada com um intervalo de datas de um ano). Desculpe pela confusão sobre isso.

Para aqueles que otimizam o restante da consulta para mim, posso ver o que as pessoas estão dizendo usando, < >mas considere o seguinte:

  1. Os parâmetros que são passados ​​são um intervalo de datas (por exemplo, 1º ao final deste mês)
  2. A data inicial na tabela pode aparecer antes ou durante o intervalo de datas dos parâmetros (por exemplo, apenas a data final está no intervalo de datas)
  3. A data final na tabela pode aparecer durante ou após o intervalo de datas dos parâmetros (por exemplo, apenas a data inicial está no intervalo de datas)
  4. Por fim, as datas de início e término na tabela estão no intervalo de datas dos parâmetros.

Pessoalmente, diante do exposto, nunca consegui uma < >solução para funcionar. A única maneira de fazê-lo funcionar corretamente e não perder nada é usando um CTE e dizendo where d.[Date] BETWEEN t.StartDate AND t.EndDate.

Eu espero que isso esclareça as coisas. Obrigado novamente.

sql-server-2005 performance
  • 5 5 respostas
  • 1033 Views

5 respostas

  • Voted
  1. Best Answer
    gbn
    2011-08-19T12:12:39+08:002011-08-19T12:12:39+08:00

    Você pode executar as etapas 1 e 2: mas use a técnica DATEADD/DATEDIFF conforme esta: Como obter a data atual sem a parte do tempo

    Você provavelmente não conseguirá indexar a coluna computada porque ela não será determinística com o método varchar

    • 5
  2. mrdenny
    2011-08-19T12:37:04+08:002011-08-19T12:37:04+08:00

    Você deve ser capaz de usar colunas computadas que você pode indexar. Eles devem ser determinísticos, pois você está saindo de um valor estático. Pode depender de como você obtém o valor na coluna calculada para saber se funcionará.

    • 4
  3. Mark Storey-Smith
    2011-08-19T15:51:49+08:002011-08-19T15:51:49+08:00

    Posso estar errado, mas parece que isso foi muito complicado/mal compreendido ou simplesmente confuso pelo CTE em sua pergunta original. Pelos comentários que você adicionou a várias respostas, parece que:

    • Você tem uma tabela que inclui duas colunas do tipo DateTime, StartDate e EndDate. Isso inclui valores de tempo, ou seja, a parte do tempo não é fixada em um valor conhecido como '00:00:00'.
    • Você deseja encontrar a contagem de registros em sua tabela que possuem valores StartDate e EndDate que estão dentro do intervalo definido pelos parâmetros @StartDate e @EndDate

    Se eu perdi o ponto, espero que você possa pelo menos usar o seguinte script para criar alguns dados de teste :)

    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[MyTable]') AND type in (N'U'))
    DROP TABLE [dbo].[MyTable]
    GO
    
    CREATE TABLE dbo.MyTable
    (
        [id] INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
        , [StartDate] DATETIME
        , [EndDate] DATETIME
    )
    GO
    
    CREATE INDEX IX_MyTable_StartDate_EndDate ON dbo.MyTable ([StartDate] ASC, [EndDate] ASC)
    GO
    
    INSERT dbo.MyTable 
    (
        [StartDate]
        , [EndDate]
    )
    VALUES
    (
        DATEADD(MI, (ABS(CHECKSUM(NEWID())) % 1339), DATEADD(DAY, -(ABS(CHECKSUM(NEWID())) % 500), GETDATE()))
        , DATEADD(MI, (ABS(CHECKSUM(NEWID())) % 1339), DATEADD(DAY, (ABS(CHECKSUM(NEWID())) % 500), GETDATE()))
    )
    GO 10000
    

    Não é este, portanto, um caso simples de:

    DECLARE 
        @StartDate CHAR(8), @EndDate CHAR(8) -- Date only values passed to procedure
        , @StartDateTime DATETIME, @EndDateTime DATETIME -- Internal DateTime values
    
    SELECT 
        @StartDate = '20110101'
        , @EndDate = '20110831'
    
    SELECT
        @StartDateTime = CAST(@StartDate AS DATETIME) -- '2011-01-01 00:00:00'
        , @EndDateTime = DATEADD(DAY, 1, CAST(@EndDate AS DATETIME)) -- '2011-09-01 00:00:00'
    
    SELECT
        COUNT([id])
    FROM
        dbo.MyTable
    WHERE
        StartDate >= @StartDateTime
    AND
        EndDate < @EndDateTime 
    

    EDIT: perdi uma otimização óbvia na consulta acima

    SELECT
        COUNT([id])
    FROM
        dbo.MyTable
    WHERE
        StartDate BETWEEN @StartDateTime AND @EndDatetime
    AND
        EndDate < @EndDateTime
    
    • 3
  4. Richard
    2011-08-19T12:45:05+08:002011-08-19T12:45:05+08:00

    Como mencionei, em última análise, tentaria me livrar da aplicação cruzada.

    Pelo que pude perceber, você terminará com linhas da tabela "table" que têm uma data de início e uma data de término antes/depois (respectivamente) de alguma linha na tabela Dates. Por causa de sua aplicação cruzada, você multiplicará os resultados da "tabela" pelo número de linhas correspondentes na tabela "Datas". Então, por causa do Distinct, você mesclará essa multiplicação em uma única linha. (É aí que vejo a ineficiência.)

    Por que não apenas fazer isso:

    DECLARE @MinDate AS DATETIME
    DECLARE @MaxDate AS DATETIME
    
    SELECT 
        @MinDate = MIN(d.StartDate), 
        @MaxDate = MAX(d.EndDate)
    FROM Dates d
    
    SELECT DISTINCT ID
    FROM table t
    WHERE 
        DATEADD(day, DATEDIFF(day, 0, t.StartDate), 0) < @MaxDate OR
        DATEADD(day, DATEDIFF(day, 0, t.EndDate), 0) > @MinDate 
    

    Advertência 1:

    Isso não funcionará se houver datas na tabela "tabela" que estiverem entre as datas mínima e máxima, mas não cercarem uma data na tabela Datas. Então, se isso funciona é baseado completamente em como seu CTE é construído. (Como não tenho a fonte completa, devo presumir que ela foi construída a partir da tabela "mesa".

    Exemplo:

    Se "Tabela" tiver uma linha com StartDate/EndDate de 18/19 de agosto (respectivamente), mas o CTE for criado para que não haja 18 de agosto nem 19 de agosto no conjunto de resultados de Datas, isso não funcionará.

    Advertência 2:

    Não tenho certeza se essas comparações > e < estão corretas. Preciso de dados de amostra para validar isso.

    • 2
  5. Thiago Dantas
    2011-08-19T13:28:07+08:002011-08-19T13:28:07+08:00

    Eu sinto sua dor. Eu escrevi o seguinte para esse tipo de tarefa, eu uso regularmente

    DECLARE @StartDate DATETIME;
    DECLARE @EndDate DATETIME; -- these should be typed, no hour
    
    SET @StartDate = '2011-01-01';
    SET @EndDate = '2011-01-31';
    
    WITH TALLY AS -- GENERATE AN ON THE FLY TALLY TABLE WITH REQUIRED AMOUNT OF ROWS
    (
        SELECT TOP (DATEDIFF(DD,@StartDate,@EndDate)+1) ROW_NUMBER() OVER (ORDER BY (SELECT 1))-1 N FROM sys.objects A
    ),   DATES AS -- GENERATE ALL D, D+1 POSSIBILITIES, YOU CAN ADJUST TO ADD 23:59:59.999 INSTEAD OF A WHOLE DAY
    (
        SELECT DATEADD(DD,N,@StartDate) StartDate,DATEADD(DD,N+1,@EndDate) EndDate FROM TALLY
    )
    SELECT DISTINCT ID
    FROM table t
    INNER JOIN DATES d ON t.YourDateWithHours BETWEEN d.StartDate AND d.EndDate -- THIS IS SARGABLE AND DETERMINISTIC, INDEXES WILL BE USED
    
    • -1

relate perguntas

  • Como você ajusta o MySQL para uma carga de trabalho pesada do InnoDB?

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

  • Downgrade do SQL Server 2008 para 2005

  • Onde posso encontrar o log lento do mysql?

  • Como posso otimizar um mysqldump de um banco de dados grande?

Sidebar

Stats

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

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

    • 4 respostas
  • Marko Smith

    Como você mostra o SQL em execução em um banco de dados Oracle?

    • 2 respostas
  • Marko Smith

    Como selecionar a primeira linha de cada grupo?

    • 6 respostas
  • Marko Smith

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

    • 10 respostas
  • Marko Smith

    Posso ver Consultas Históricas executadas em um banco de dados SQL Server?

    • 6 respostas
  • Marko Smith

    Como uso currval() no PostgreSQL para obter o último id inserido?

    • 10 respostas
  • Marko Smith

    Como executar o psql no Mac OS X?

    • 11 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
  • Marko Smith

    Passando parâmetros de array para um procedimento armazenado

    • 12 respostas
  • Martin Hope
    Manuel Leduc Restrição exclusiva de várias colunas do PostgreSQL e valores NULL 2011-12-28 01:10:21 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Stuart Blackler Quando uma chave primária deve ser declarada sem cluster? 2011-11-11 13:31:59 +0800 CST
  • Martin Hope
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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
  • Martin Hope
    BrunoLM Guid vs INT - Qual é melhor como chave primária? 2011-01-05 23:46:34 +0800 CST
  • Martin Hope
    bernd_k Quando devo usar uma restrição exclusiva em vez de um índice exclusivo? 2011-01-05 02:32:27 +0800 CST
  • Martin Hope
    Patrick Como posso otimizar um mysqldump de um banco de dados grande? 2011-01-04 13:13:48 +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