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 / 9159
Accepted
Ben Brocka
Ben Brocka
Asked: 2011-12-15 07:18:33 +0800 CST2011-12-15 07:18:33 +0800 CST 2011-12-15 07:18:33 +0800 CST

As 2 primeiras linhas por partição de uma diferença de data de valor absoluto

  • 772

Eu tenho um banco de dados de imagens de câmeras de segurança em um banco de dados desnormalizado. Eu tenho locais que possuem várias câmeras que tiram várias imagens.

Location + Camera + image capture_date é a chave primária agrupada e, atualmente, o único índice na tabela. O kicker está procurando uma única câmera leva <1 milissegundo do SSMS e ~ 70ms do meu aplicativo da web. Minhas soluções CTE de trabalho atuais levam cerca de 3 minutos para três câmeras .

Para dar uma visão geral das câmeras em um local, preciso selecionar 2 imagens de cada câmera mais próximas de uma determinada data (como a data atual). Por isso preciso de um valor absoluto (datas anteriores ou posteriores à data de busca são igualmente válidas), por isso estou buscando pelo menor ABS(@date -capture_date).

Aqui está o código atual. Funciona, mas não é SARGable e é extremamente lento. Também preciso apenas das 2 primeiras linhas por câmera no CTE, pois pode haver centenas de milhares de imagens por partição.

DECLARE @date datetime,
        @location varchar(4)
SET     @date ='2011-12-13 12:00:00'
SET     @location='CS01';
WITH CTE AS (
    SELECT
        *,
        ROW_NUMBER() OVER (PARTITION  BY Camera ORDER BY  abs(datediff(second,@date, [capture_date]))) AS Ranking
    FROM rs_camera_pictures
    WHERE 
        location=@location)
SELECT * FROM CTE WHERE Ranking <= 2
sql-server sql-server-2005
  • 4 4 respostas
  • 1396 Views

4 respostas

  • Voted
  1. Best Answer
    JNK
    2011-12-15T07:32:20+08:002011-12-15T07:32:20+08:00

    Este é apenas um ponto de partida e provavelmente precisará de alguns ajustes.

    Essencialmente, isso fornecerá as 4 datas de captura mais próximas da data especificada (2 mais próximas depois e 2 mais próximas antes).

    Você precisará adicionar alguma lógica à sua seleção externa para escolher quais usar, mas estará fazendo um DATEDIFFem 4 campos em vez de todos eles.

    WITH CTE AS
    (
    SELECT camera, MIN(r1.capture_date) as 'After', MAX(r2.capture_date) as 'Before'
    FROM rs_camera_pictures r1
    INNER JOIN rs_camera_pictures r2
        ON r1.location = r2.location
        AND r1.camera = r2.camera
    WHERE r1.capture_date > @date
    AND r2.capture_date < @date
    GROUP BY camera
    UNION ALL
    SELECT camera, MIN(r1.capture_date) as 'After', MAX(r2.capture_date) as 'Before'
    FROM rs_camera_pictures r1
    INNER JOIN rs_camera_pictures r2
        ON r1.location = r2.location
        AND r1.camera = r2.camera
    INNER JOIN CTE c
        ON r1.location = c.location
        AND r1.camera = c.camera
    WHERE r1.capture_date > c.[After]
    AND r2.capture_date < c.Before
    GROUP BY camera
    )
    
    • 1
  2. MartinC
    2011-12-15T08:38:57+08:002011-12-15T08:38:57+08:00

    Isso deve retornar quatro linhas por câmera no local selecionado e, em seguida, classificá-las para retornar as duas melhores para cada câmera.

    LocationCamera é a lista distinta das câmeras para um local.

    DECLARE @date datetime,
            @location varchar(4)
    SET     @date ='2011-12-13 12:00:00'
    SET     @location='CS01';
    
    SELECT      Location,Camera,Capture_Date,Ranking
    FROM        (
                    SELECT      Location,Camera,Capture_Date,
                                ROW_NUMBER() OVER (PARTITION  BY Camera ORDER BY  abs(datediff(second,@date, [capture_date]))) AS Ranking
                    FROM        (
                                    SELECT      L.Location,
                                                L.Camera,
                                                CP.capture_date
                                    FROM        LocationCamera  L
                                    CROSS APPLY (
                                                    SELECT      TOP (2)
                                                                CP.[capture_date]
                                                    FROM        rs_camera_pictures  CP
                                                    WHERE       L.Location          = CP.Location
                                                    AND         L.Camera            = CP.Camera
                                                    AND         CP.capture_date     >= @date
                                                    ORDER BY    [capture_date]
                                                )   TopN
                                    WHERE       L.Location      = @Location
                                    UNION ALL
                                    SELECT      L.Location,
                                                L.Camera,
                                                CP.[capture_date]
                                    FROM        LocationCamera  L
                                    CROSS APPLY (
                                                    SELECT      TOP (2)
                                                                CP.[capture_date]
                                                    FROM        rs_camera_pictures  CP
                                                    WHERE       L.Location          = CP.Location
                                                    AND         L.Camera            = CP.Camera
                                                    AND         CP.capture_date     < @date
                                                    ORDER BY    [capture_date]      DESC
                                                )   BottomN
                                    WHERE       L.Location      = @location
                                )   D
                )   R
    WHERE       Ranking <= 2
    
    • 1
  3. Jonathan Van Matre
    2011-12-15T13:27:05+08:002011-12-15T13:27:05+08:00

    Pelo que sei (além de algumas pesquisas no Google e hacking para ver se havia uma maneira que eu ainda não conhecia), não há solução que evite o ABS não SARGable (DATEDIFF e supere o que você tem agora.

    Portanto, se você deve implementar uma pesquisa não SARGable, a coisa mais importante a fazer é encontrar maneiras SARGable de restringir o tamanho do conjunto. No momento, sua cláusula WHERE inclui uma cláusula SARGable, mas se estivermos falando de potencialmente centenas de milhares de linhas por câmera (ou seja, milhões em potencial por local), faz sentido reduzir ainda mais o domínio do problema.

    Minha recomendação é escolher um valor razoável para a distância máxima de pesquisa e estabelecer um limite superior e inferior na data. Por exemplo, digamos que seu sistema normalmente tiraria uma foto pelo menos a cada 5 minutos, a menos que a câmera esteja falhando. Podemos definir um limite superior e inferior de 6 minutos (para permitir "jitter" no tempo) e apenas classificar as imagens dentro desses limites. Isso ficaria assim:

    DECLARE @date datetime,
            @location varchar(4) ,
            @dateUB DATETIME,
            @dateLB DATETIME
    SET     @date ='2011-12-13 12:00:00'
    SET     @DateUB = DATEADD(minute, 6, @matchDate)
    SET     @DateLB = DATEADD(minute, -6, @matchDate)
    SET     @location='CS01';
    WITH CTE AS (
        SELECT
            *,
            ROW_NUMBER() OVER (PARTITION  BY Camera ORDER BY  abs(datediff(second,@date, [capture_date]))) AS Ranking
        FROM rs_camera_pictures
        WHERE 
            location=@location
        AND capture_date BETWEEN @dateUB AND @dateLB )
    SELECT * FROM CTE WHERE Ranking <= 2
    

    Se capture_date e location forem cobertos por índices, isso deve proporcionar uma melhoria significativa.

    • 1
  4. db2
    2011-12-15T07:47:07+08:002011-12-15T07:47:07+08:00

    Talvez pegue os 2 primeiros em ambas as direções a partir da data selecionada e, em seguida, pegue os 2 primeiros a partir disso.

    DECLARE @date datetime,
            @location varchar(4)
    SET     @date ='2011-12-13 12:00:00'
    SET     @location='CS01';
    WITH candidates AS (
        SELECT * FROM (
            SELECT TOP 2 *
            FROM rs_camera_pictures
            WHERE location=@location
                AND capture_date <= @date
            ORDER BY capture_date DESC
        ) [before]
        UNION
        SELECT * FROM (
            SELECT TOP 2 *
            FROM rs_camera_pictures
            WHERE location=@location
                AND capture_date >= @date
            ORDER BY capture_date ASC
        ) [after]
    ),
    CTE AS (
        SELECT
            *,
            ROW_NUMBER() OVER (PARTITION  BY Camera ORDER BY  abs(datediff(second,@date, [capture_date]))) AS Ranking
        FROM candidates
        WHERE 
            location=@location
    )
    SELECT * FROM CTE WHERE Ranking <= 2
    
    • 0

relate perguntas

  • 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

  • Downgrade do SQL Server 2008 para 2005

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