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 / user-52150

mpag's questions

Martin Hope
mpag
Asked: 2016-08-27 16:49:29 +0800 CST

tSQL Stored Procedure com CTE; Instrução CASE em WHERE retardando a execução

  • 3

Eu tenho um procedimento armazenado definido pelo usuário Ao chamar sem passar valores explícitos, desejo apenas passar todos os locais (nvarchar(50)), que é o campo de chave primária de uma tabela: Monitor_Locations (com ~ 850 entradas)

Uma parte do SP é definida da seguinte forma (recortada).

ALTER PROCEDURE [dbo].[dev_Tech@Locs2b] ( --CREATE or ALTER
     @Locations as nvarchar(MAX) = NULL -- = 'GG1,BenBr14,BenBr00,YB_ToeDrain_Base'
    ,@rangeStart as DateTime = '1970-01-01'
    ,@rangeEnd as DateTime = '2099-12-31'
) AS BEGIN
SET NOCOUNT ON; --otherwise concrete5 chokes for multi-table returns.
DECLARE @loclist as TABLE (
    Location nvarchar(50) PRIMARY KEY
)
IF @Locations is NULL
    INSERT INTO @loclist(Location)
        SELECT Location from Monitor_Locations order by Location
ELSE --irrelevant for this question
    INSERT INTO @loclist(Location)
        SELECT
            ML.Location
        FROM Monitor_Locations as ML join
            tvf_splitstring(@Locations) as ss ON 
                ML.Location=ss.Item OR 
                ML.Location like ss.Item+'[_]%'
        ORDER BY ML.Location;
With Deploys as (
    SELECT
        D.Location,
        MIN(D.Start) as Start,
        MAX(D.[Stop]) as Stop
    FROM
        Deployments as D 
    WHERE 
        D.Stop is not NULL
)

...fazer um monte de outras coisas...

para melhorar a velocidade do procedimento armazenado quando uma lista restrita de sites é enviada para o SP, eu queria substituir a cláusula WHERE por

WHERE 
    CASE
        WHEN D.Stop IS NULL THEN 0
        WHEN @Locations IS NULL THEN 1 -- full list, so binding to another list doesn't do us any good.
        WHEN EXISTS (SELECT 1 from (SELECT Location from @loclist as l where l.Location=D.Location) as ll) THEN 1 --ELSE NULL which is not 1
    END=1

mas onde antes o SP levava de 6 a 8 segundos para ser executado, agora leva 2,5 minutos (para chamadas sem uma lista restritiva). Achei que levaria aproximadamente a mesma quantidade de tempo em cada sentido para a lista completa, pois a segunda cláusula do CASE deveria ser disparada muito rapidamente e a terceira cláusula nunca deveria ser examinada.

Então o que está acontecendo? Este código:

WHERE 
    CASE
        WHEN D.Stop IS NULL THEN NULL
        WHEN @Locations IS NULL THEN 1 -- full list, so binding to another list doesn't do us any good.
        WHEN EXISTS (SELECT 1 from (SELECT Location from @loclist as l where l.Location=D.Location) as ll) THEN 1 --else null
    END is not null

Leva um tempo de execução de aproximadamente 10 minutos com este plano:

CasoOnde

Para contrastar, aqui está o WHERE D.Stop is not NULLplano (6s): PadrãoOnde

Em um ponto, este SP estava demorando 1 segundo com esta versão, mas mudando o SP e voltando novamente, demorou 6 segundos novamente. Conforme mencionado nas respostas, isso provavelmente ocorreu devido à detecção de parâmetros.

tempos de execução

Meu objetivo de tempo de execução é inferior a 2 segundos, pois este será um SP executado com frequência em um aplicativo da Web que o usa para preencher e restringir outras seleções do usuário. Basicamente, não quero que isso seja um gargalo perceptível. Os tempos iniciais de execução foram da ordem de 3 minutos, mas depois de adicionar ou alterar alguns índices, caiu para a faixa de 6 a 8 segundos.

Na segunda-feira (2016-08-29), antes de grandes alterações WHERE simples sem parâmetros de entrada: 5s WHERE simples com rangeStart e rangeEnd: 4s WHERE simples com @Locations definido como uma variável CSV de 7 elementos CASEd WHERE: até 10 minutos

Depois de retrabalhar a função CLR (veja minha resposta abaixo) Terça-feira (30/08/2016) Simples ou CASEd WHERE sem parâmetros de entrada OU Simples ou CASEd WHERE com rangeStart e rangeEnd: 3s Simples ou CASEd WHERE com 7 elementos @Locations: 0 -1s

Depois de migrar a variável de tabela @loclist para a tabela temporária #loclist Todos os WHEREs/parâmetros testados: 0-1s

t-sql sql-server-2008-r2
  • 3 respostas
  • 1137 Views
Martin Hope
mpag
Asked: 2016-02-10 10:09:46 +0800 CST

SSMS: importar de arquivo simples (.csv)

  • 3

No SQL Server Management Studio (SSMS) 2008 R2, desejo importar um CSV não formatado corretamente para uma tabela de banco de dados. Eu estava tentando usar o assistente em <database name>-> Tasks-> Import Data.

Diferenças do "padrão" CSV

  1. valores nulos são representados por um espaço entre vírgulas
  2. alguns campos têm vírgulas no meio deles e não estão entre aspas
  3. há uma vírgula terminal em todas as linhas, exceto na linha de cabeçalho (WTF??)

Acabei resolvendo esses problemas manualmente editando o CSV antes da importação. O problema 2 foi corrigido substituindo vírgulas por traços para as 4 famílias de valores de células que estavam causando isso. Problema 3 Eu resolvi com uma pesquisa e substituição para essas vírgulas terminais. Problema 1, que era um problema para campos numéricos, também com pesquisa e substituição , ,-> ,,.

Quando meu arquivo finalmente foi importado corretamente, os valores nulos foram substituídos por zeros, embora eu tivesse permitido valores nulos nas definições de campo.

Minha pergunta básica: existe uma maneira de alterar o código para CAST/ CONVERToperações durante uma importação do SSMS? A única etapa em que consegui chegar ao código SQL foi nas definições de campo da tabela criada (de Select Source Tables and Views-> Edit Mappings-> Edit SQL- que estava disponível se e somente se eu não tivesse alterado o nome da tabela de destino na Select Source Tablespágina), mas isso foi apenas para a CREATE TABLEdefinição e não abordou o processo de importação. Realmente parece-me que devo permitir que uma string de espaço de um único caractere seja convertida em um valor nulo quando convertida em um número (em vez disso, o assistente falha e informa que um valor está fora dos limites). Além disso, a string nula certamente deve ser convertida para o valor inteiro nulo, em vez de 0.

Posso salvar um pacote SSIS, mas não estava claro para mim como editar e executá-lo para permitir o que quero fazer. Existe um arquivo de modelo em algum lugar que eu possa editar para permitir que strings nulas sejam convertidas em valores inteiros nulos (como algo aqui .... )? Existe uma maneira de usar partes do assistente de importação para gerar código tSQL? Em vez disso, devo usar uma BULK INSERTinstrução em vez do assistente?

sql-server-2008-r2 ssis
  • 1 respostas
  • 1401 Views
Martin Hope
mpag
Asked: 2015-12-12 13:59:33 +0800 CST

Implementação Lead/Lag no SQL Server 2008 R2: memória máxima excedida

  • 7

Fundo

Estou tentando estabelecer uma sequência de "visitas", em que se um animal for detectado essencialmente no mesmo local ( General_Location) conta como uma única visita, mas se for para outro lugar e depois voltar, é uma visita adicional ao mesmo local. Portanto, se o animal for detectado em uma Locationsequência
A1, A2, A3, A3, A3, A1, B2, D4, A2
em que, por exemplo, todos os locais A(n) pertencem a General_Location"A", isso terá as primeiras 6 detecções como visita 1 (@A), a seguir como visita 2 (@B), a seguir como visita 3 (@D), a seguir como visita 4 (voltar @A).

Como LAGe LEADnão estão disponíveis no SQL Server 2008R2 (nem está UNBOUNDED PRECEDINGna PARTITIONcláusula ing), estou tentando uma solução alternativa, conforme descrito nesta entrada de blog do SQL Authority .

Estou com problemas de memória (para não mencionar o tempo de computação) com o seguinte:

WITH s AS (
    SELECT
        RANK() OVER (PARTITION BY det.Technology, det.XmitID ORDER BY DetectDate ASC, ReceiverID ASC) as DetID,
        COALESCE(TA.AnimalID, det.Technology+'-'+cast(da.XmitID AS nvarchar), 'BSVALUE999') as AnimalID,
        det.Technology, det.XmitID, DetectDate, det.location as Location, RL.General_Location as GLocation, ReceiverID
    FROM
        Detections_with_Location as det JOIN
        Receiver_Locations as RL
            ON det.Location=RL.Location LEFT OUTER JOIN
        Tagged_Animal as TA
            ON det.AnimalID=TA.AnimalID
)
INSERT INTO ##ttOrder_det (AnimalID, Technology, XmitID, DD, Location, GLocation, ReceiverID, DetID, PrevDD, BinInc)
    SELECT 
        s1.AnimalID, --was a coalesce
        s1.Technology, s1.XmitID, s1.DetectDate, s1.Location, s1.GLocation, s1.ReceiverID,
        s1.DetID, 
        sLAG.DetectDate,
        CASE WHEN sLAG.DetectDate IS NULL
            THEN 1 
            ELSE CASE WHEN sLAG.GLocation = s1.GLocation
                THEN 0
                ELSE 1
            END
        END AS BinInc
    FROM s as s1
    LEFT OUTER JOIN s AS sLAG ON
        s1.DetID = sLAG.DetID + 1 AND
        s1.AnimalID= sLAG.AnimalID --and s.Technology=sLAG.Technology and s.XmitID=sLAG.XmitID;

Como vários usuários (@MartinSmith, @Frisbee) mencionaram ou aludiram, o uso de AnimalIDnão é a chave primária completa de Tagged_Animal, nem é definido em uma restrição UNIQUE. No entanto, a contagem de linhas na tabela onde A.AnimalID=B.AnimalID AND A.TagSN<B.TagSNé (atualmente) zero. Para tornar essa consulta robusta, eu teria que fazer com que fosse único (ou apenas retirar TagSN do PK).

Definições de tabela e índice

##ttOrder_det (tabela temporária)

Os índices são criados atualmente antes de preencher a tabela; Estou passando por testes em que mudo a criação NONCLUSTEREDnão UNIQUEindexada para uma posição depois que a tabela temporária é preenchida.

CREATE TABLE ##ttOrder_det (
    AnimalID nvarchar(50) not null,
    Technology varchar(25) not null,
    XmitID int not null,
    DD DateTime not null,
    [Location] [nvarchar](255) NULL,
    [GLocation] nvarchar(255) NULL,
    PrevDD DateTime NULL,
    ReceiverID int not null,
    DetID int NOT NULL,
    BinInc int NULL,
    BinNum int NULL,
CONSTRAINT [PK_ttRDA] PRIMARY KEY CLUSTERED 
    ([AnimalID] ASC, [DD] ASC, ReceiverID ASC)
    WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY];
GO
CREATE NONCLUSTERED INDEX NIX_F on ##ttOrder_det (AnimalID ASC);
CREATE NONCLUSTERED INDEX NIX_VTC ON ##ttOrder_det (ReceiverID ASC, AnimalID ASC);
CREATE NONCLUSTERED INDEX NIX_TCD ON ##ttOrder_det (AnimalID ASC, DD ASC);
CREATE NONCLUSTERED INDEX NIX_R ON ##ttOrder_det (DetID ASC);
CREATE NONCLUSTERED INDEX NIX_A ON ##ttOrder_det (GLocation ASC);
CREATE NONCLUSTERED INDEX NIX_DD ON ##ttOrder_det (DD, PrevDD);
CREATE UNIQUE INDEX UX_CTR ON ##ttOrder_det (AnimalID ASC, DetID ASC);
CREATE NONCLUSTERED INDEX NIX_Bi ON ##ttOrder_det (BinInc ASC);
CREATE NONCLUSTERED INDEX NIX_CT ON ##ttOrder_det (XmitID ASC, Technology ASC);

Tagged_Animal

CREATE TABLE [dbo].[Tagged_Animal](
    [DateTagged] [datetime] NULL,
    [AnimalID] [nvarchar](50) NOT NULL,
    [TagSN] [nvarchar](50) NOT NULL,
    [XmitID] [int] NULL,
    [Technology] [varchar](25) NULL,
    [Animal_SubType] [nvarchar](50) NULL,
    [Species] [nvarchar](30) NULL,
    [StudyID] [nvarchar](50) NULL,
    [Weight] [float] NULL,
    [Length] [int] NULL,
    [Length_Type] [nvarchar](50) NULL,
    [Date_Released] [datetime] NULL,
    [Release_Location] [nvarchar](50) NULL,
    [Lat] [float] NULL,
    [Lon] [float] NULL,
    [Course_Dist_km] [float] NULL,
    [Sex] [nvarchar](255) NULL,
    [Life_Stage] [nvarchar](255) NULL,
    [Marking_Method] [nvarchar](255) NULL,
    [Tag_Type] [varchar](30) NULL,
    [Notes] [nvarchar](255) NULL,
 CONSTRAINT [PK_tbl_Tagged_Animal] PRIMARY KEY CLUSTERED 
(
    [AnimalID] ASC,
    [TagSN] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [I_TF_TagCode] ON [dbo].[Tagged_Animal] 
(
    [XmitID] ASC,
    [Technology] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

Detecções_com_Localização

CREATE TABLE [dbo].[Detections_with_Location](
    [AnimalID] [nvarchar](50) NOT NULL,
    [XmitID] [int] NOT NULL,
    [Technology] [varchar](25) NOT NULL,
    [DetectDate] [datetime] NOT NULL,
    [ReceiverID] [int] NOT NULL,
    [Data] [float] NULL,
    [Units] [varchar](50) NULL,
    [Location] [nvarchar](255) NULL,
    [StartD] [datetime] NULL,
    [StopD] [datetime] NULL,
    [fname] [nvarchar](255) NULL,
    [notes] [nvarchar](max) NULL,
 CONSTRAINT [PK_dlwk] PRIMARY KEY CLUSTERED 
(
    [ReceiverID] ASC,
    [Technology] ASC,
    [XmitID] ASC,
    [DetectDate] ASC,
    [AnimalID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [NIX_VTC] ON [dbo].[Detections_with_Location] 
(
    [ReceiverID] ASC,
    [AnimalID] ASC,
    [XmitID] ASC,
    [Technology] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [NIX_TCpi] ON [dbo].[Detections_with_Location] 
(
    [XmitID] ASC,
    [Technology] ASC
)
INCLUDE ( [DetectDate],
[ReceiverID],
[Data],
[Units],
[Location]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [NIX_TCD] ON [dbo].[Detections_with_Location] 
(
    [AnimalID] ASC,
    [XmitID] ASC,
    [Technology] ASC,
    [DetectDate] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [NIX_F] ON [dbo].[Detections_with_Location] 
(
    [AnimalID] ASC
)
INCLUDE ( [XmitID],
[Technology],
[DetectDate],
[ReceiverID],
[Data],
[Units],
[Location]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

CREATE NONCLUSTERED INDEX [NIX_DSS] ON [dbo].[Detections_with_Location] 
(
    [ReceiverID] ASC,
    [Location] ASC,
    [StartD] ASC,
    [StopD] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

Receptor_Locais

CREATE TABLE [dbo].[Receiver_Locations](
    [Region] [nvarchar](50) NULL,
    [Location_Long] [nvarchar](50) NULL,
    [Location] [nvarchar](50) NOT NULL,
    [Lat] [float] NULL,
    [Lon] [float] NULL,
    [Altitude] [float] NULL,
    [Elevation] [float] NULL,
    [RiverKm] [float] NULL,
    [LocationType] [nvarchar](50) NULL,
    [General_Location] [nvarchar](50) NULL,
    [Nearest_Access] [nvarchar](50) NULL,
    [Responsible_Agent] [nvarchar](50) NULL,
    [Agent_Phone] [nvarchar](255) NULL,
    [Agent_Email] [nvarchar](255) NULL,
 CONSTRAINT [PK_tbl_Receiver_Locations] PRIMARY KEY CLUSTERED 
(
    [Location] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]


Tamanhos de tabela

Tagged_Animals: 10 mil
Detections_with_Location: mais de 46 milhões de entradas
Receiver_Locations: 800

Erros Específicos Recebidos

  1. Não foi possível alocar espaço para o objeto 'dbo.SORT armazenamento de execução temporária: 140737631617024' no banco de dados 'tempdb' porque o grupo de arquivos 'PRIMARY' está cheio. Crie espaço em disco excluindo arquivos desnecessários, descartando objetos no grupo de arquivos, adicionando arquivos adicionais ao grupo de arquivos ou definindo o crescimento automático para arquivos existentes no grupo de arquivos.

  2. O log de transações do banco de dados 'tempdb' está cheio. Para descobrir por que o espaço no log não pode ser reutilizado, consulte a coluna log_reuse_wait_desc em sys.databases (tempdb ACTIVE_TRANSACTION)

  3. Ocorreu um erro ao executar o lote. A mensagem de erro é: Exceção do tipo 'System.OutOfMemoryException' foi lançada --(se estiver fazendo suma seleção direta após cerca de 33 milhões de registros).

(Estimado) Plano de Execução Resumo do código inicial

INSERTcusto 0%
SEQUENCEcusto 0%, mas com base em 9 subetapas diferentes. Essas subetapas (com custos típicos) são um Index Insert(2%), seguido por Sort(8%), seguido por Table Spool(2%). NIX_Atem um custo de 9% para Index Inserte NIX_TCDnem NIX_Ftem Sortdegrau; O Table Spoolpara NIX_Fé grátis.
O Clustered Index Insertcusto é de 10%.
Há também um Sortcusto de 2% e um Parallelismcusto de 1% para distribuição de streams.
Para o SEQUENCEcusto, parece aumentar para 95%, com outras etapas custando 13%, então obviamente há alguns "erros" de arredondamento em algum lugar, provavelmente principalmente nos 14% da sequência Index Insert- Sort- .Table Spool

Notas/Ref.

Implementação LAG/LEAD baseada na entrada do blog SQL Authority
Veja também este Stackexchange Thread

Minhas perguntas

  1. Alguma sugestão para melhorar?

  2. Posso particionar também quando juntar as cópias de s?

  3. As coisas melhorariam se eu scriasse uma tabela temporária discreta e a indexasse apropriadamente?

  4. Seria mais eficiente criar os não- UNIQUEíndices nas tabelas temporárias depois que todas as inserções forem realizadas? Presumo que os índices UNIQUE(e, portanto, PRIMARY KEY) devem ser criados antecipadamente para evitar violações de restrição chave.

Para responder a uma das minhas próprias perguntas

  1. Sim, sim, seria. Depois de mais otimizações
    • 21 minutos para preencher a tabela temporária com dados
    • 1 minuto para indexar

Anteriormente, esse processo durava pelo menos 1,5 horas, apresentava erros e não produzia uma tabela de resultados. Antes de começar a mexer na lógica da consulta, na verdade, levaria mais de 4 horas antes de ocorrer um erro.

Especificações do servidor:

Processador: Xeon E3-1240 V2 a 3,4 GHz (4 núcleos/8 threads)
Memória: 16 GB
Arquivo de paginação: 16 GB em SSD de 111 GB (52 GB grátis)
tempdb + meu banco de dados em SSD de 223 GB (119 GB grátis)


Status atual

Veja minha solução/resposta postada.

sql-server sql-server-2008-r2
  • 1 respostas
  • 2248 Views
Martin Hope
mpag
Asked: 2015-09-30 20:14:36 +0800 CST

Access (Jet) SQL: carimbos de data e hora na TabelaB flanqueando cada carimbo de data e hora na TabelaA

  • 21

Primeiras palavras

Você pode ignorar com segurança as seções abaixo (e incluindo) JOINs: Starting Off se você quiser apenas decifrar o código. O pano de fundo e os resultados servem apenas como contexto. Por favor, olhe o histórico de edições antes de 2015-10-06 se você quiser ver como era o código inicialmente.


Objetivo

Por fim, quero calcular as coordenadas GPS interpoladas para o transmissor ( Xou Xmit) com base nos carimbos DateTime dos dados GPS disponíveis na tabela SecondTableque flanqueiam diretamente a observação na tabela FirstTable.

Meu objetivo imediato para atingir o objetivo final é descobrir a melhor forma de se juntar FirstTablepara SecondTableobter esses pontos de tempo de flanco. Mais tarde, posso usar essas informações e calcular coordenadas GPS intermediárias assumindo um ajuste linear ao longo de um sistema de coordenadas equiretangulares (palavras elegantes para dizer que não me importo que a Terra seja uma esfera nessa escala).


Perguntas

  1. Existe uma maneira mais eficiente de gerar os carimbos de data/hora antes e depois mais próximos?
    • Corrigido por mim mesmo, apenas pegando o "depois" e, em seguida, obtendo o "antes" apenas conforme relacionado ao "depois".
  2. Existe uma maneira mais intuitiva que não envolva a (A<>B OR A=B)estrutura.
    • Byrdzeye forneceu as alternativas básicas, no entanto, minha experiência no "mundo real" não se alinhou com todas as 4 de suas estratégias de junção com o mesmo desempenho. Mas todo o crédito a ele por abordar os estilos alternativos de junção.
  3. Quaisquer outros pensamentos, truques e conselhos que você possa ter.
    • Até agora, tanto byrdzeye quanto Phrancis foram bastante úteis a esse respeito. Achei que o conselho de Phrancis foi excelentemente apresentado e forneceu ajuda em um estágio crítico, então vou dar a ele uma vantagem aqui.

Eu ainda gostaria de qualquer ajuda adicional que eu possa receber em relação à pergunta 3. Os marcadores refletem quem eu acredito que mais me ajudou na pergunta individual.


Definições de tabela

Representação semivisual

PrimeiraTabela

Fields
  RecTStamp | DateTime  --can contain milliseconds via VBA code (see Ref 1) 
  ReceivID  | LONG
  XmitID    | TEXT(25)
Keys and Indices
  PK_DT     | Primary, Unique, No Null, Compound
    XmitID    | ASC
    RecTStamp | ASC
    ReceivID  | ASC
  UK_DRX    | Unique, No Null, Compound
    RecTStamp | ASC
    ReceivID  | ASC
    XmitID    | ASC

SegundaTabela

Fields
  X_ID      | LONG AUTONUMBER -- seeded after main table has been created and already sorted on the primary key
  XTStamp   | DateTime --will not contain partial seconds
  Latitude  | Double   --these are in decimal degrees, not degrees/minutes/seconds
  Longitude | Double   --this way straight decimal math can be performed
Keys and Indices
  PK_D      | Primary, Unique, No Null, Simple
    XTStamp   | ASC
  UIDX_ID   | Unique, No Null, Simple
    X_ID      | ASC

Tabela de detalhes do receptor

Fields
  ReceivID                      | LONG
  Receiver_Location_Description | TEXT -- NULL OK
  Beginning                     | DateTime --no partial seconds
  Ending                        | DateTime --no partial seconds
  Lat                           | DOUBLE
  Lon                           | DOUBLE
Keys and Indicies
  PK_RID  | Primary, Unique, No Null, Simple
    ReceivID | ASC

tabela ValidXmitters

Field (and primary key)
  XmitID    | TEXT(25) -- primary, unique, no null, simple

violino SQL...

...para que você possa brincar com as definições e o código da tabela Esta pergunta é para o MSAccess, mas, como Phrancis apontou, não há um estilo SQL fiddle para o Access. Portanto, você deve poder acessar aqui para ver minhas definições de tabela e código com base na resposta de Phrancis :
http://sqlfiddle.com/#!6/e9942/4 (link externo)


JOINs: Começando

Minha estratégia JOIN atual de "entranhas internas"

Primeiro, crie um FirstTable_rekeyed com a ordem das colunas e a chave primária composta, (RecTStamp, ReceivID, XmitID)todas indexadas/classificadas ASC. Também criei índices em cada coluna individualmente. Em seguida, preencha-o assim.

INSERT INTO FirstTable_rekeyed (RecTStamp, ReceivID, XmitID)
  SELECT DISTINCT ROW RecTStamp, ReceivID, XmitID
  FROM FirstTable
  WHERE XmitID IN (SELECT XmitID from ValidXmitters)
  ORDER BY RecTStamp, ReceivID, XmitID;

A consulta acima preenche a nova tabela com 153.006 registros e retorna em cerca de 10 segundos.

O seguinte é concluído em um ou dois segundos quando todo esse método é agrupado em um "SELECT Count(*) FROM ( ... )" quando o método de subconsulta TOP 1 é usado

SELECT 
    ReceiverRecord.RecTStamp, 
    ReceiverRecord.ReceivID, 
    ReceiverRecord.XmitID,
    (SELECT TOP 1 XmitGPS.X_ID FROM SecondTable as XmitGPS WHERE ReceiverRecord.RecTStamp < XmitGPS.XTStamp ORDER BY XmitGPS.X_ID) AS AfterXmit_ID
    FROM FirstTable_rekeyed AS ReceiverRecord
    -- INNER JOIN SecondTable AS XmitGPS ON (ReceiverRecord.RecTStamp < XmitGPS.XTStamp)
         GROUP BY RecTStamp, ReceivID, XmitID;
-- No separate join needed for the Top 1 method, but it would be required for the other methods. 
-- Additionally no restriction of the returned set is needed if I create the _rekeyed table.
-- May not need GROUP BY either. Could try ORDER BY.
-- The three AfterXmit_ID alternatives below take longer than 3 minutes to complete (or do not ever complete).
  -- FIRST(XmitGPS.X_ID)
  -- MIN(XmitGPS.X_ID)
  -- MIN(SWITCH(XmitGPS.XTStamp > ReceiverRecord.RecTStamp, XmitGPS.X_ID, Null))

Consulta JOIN anterior "inner guts"

Primeiro (rápido... mas não bom o suficiente)

SELECT 
  A.RecTStamp,
  A.ReceivID,
  A.XmitID,
  MAX(IIF(B.XTStamp<= A.RecTStamp,B.XTStamp,Null)) as BeforeXTStamp,
  MIN(IIF(B.XTStamp > A.RecTStamp,B.XTStamp,Null)) as AfterXTStamp
FROM FirstTable as A
INNER JOIN SecondTable as B ON 
  (A.RecTStamp<>B.XTStamp OR A.RecTStamp=B.XTStamp)
GROUP BY A.RecTStamp, A.ReceivID, A.XmitID
  -- alternative for BeforeXTStamp MAX(-(B.XTStamp<=A.RecTStamp)*B.XTStamp)
  -- alternatives for AfterXTStamp (see "Aside" note below)
  -- 1.0/(MAX(1.0/(-(B.XTStamp>A.RecTStamp)*B.XTStamp)))
  -- -1.0/(MIN(1.0/((B.XTStamp>A.RecTStamp)*B.XTStamp)))

Segundo (mais lento)

SELECT
  A.RecTStamp, AbyB1.XTStamp AS BeforeXTStamp, AbyB2.XTStamp AS AfterXTStamp
FROM (FirstTable AS A INNER JOIN 
  (select top 1 B1.XTStamp, A1.RecTStamp 
   from SecondTable as B1, FirstTable as A1
   where B1.XTStamp<=A1.RecTStamp
   order by B1.XTStamp DESC) AS AbyB1 --MAX (time points before)
ON A.RecTStamp = AbyB1.RecTStamp) INNER JOIN 
  (select top 1 B2.XTStamp, A2.RecTStamp 
   from SecondTable as B2, FirstTable as A2
   where B2.XTStamp>A2.RecTStamp
   order by B2.XTStamp ASC) AS AbyB2 --MIN (time points after)
ON A.RecTStamp = AbyB2.RecTStamp; 

Fundo

Eu tenho uma tabela de telemetria (com o apelido de A) de pouco menos de 1 milhão de entradas com uma chave primária composta baseada em um DateTimecarimbo, uma ID de transmissor e uma ID de dispositivo de gravação. Devido a circunstâncias fora do meu controle, minha linguagem SQL é o Jet DB padrão no Microsoft Access (os usuários usarão 2007 e versões posteriores). Apenas cerca de 200.000 dessas entradas são relevantes para a consulta devido ao ID do transmissor.

Existe uma segunda tabela de telemetria (alias B) que envolve aproximadamente 50.000 entradas com uma única DateTimechave primária

Na primeira etapa, concentrei-me em encontrar os carimbos de data/hora mais próximos dos carimbos da primeira tabela a partir da segunda tabela.


Resultados do JOIN

Curiosidades que descobri...

...ao longo do caminho durante a depuração

É realmente estranho escrever a JOINlógica como FROM FirstTable as A INNER JOIN SecondTable as B ON (A.RecTStamp<>B.XTStamp OR A.RecTStamp=B.XTStamp)@byrdzeye apontou em um comentário (que desde então desapareceu) é uma forma de junção cruzada. Observe que substituir LEFT OUTER JOINno INNER JOINcódigo acima parece não causar impacto na quantidade ou identidade das linhas retornadas. Também não consigo deixar de fora a cláusula ON ou dizer ON (1=1). Apenas usar uma vírgula para unir (em vez de INNERou LEFT OUTER JOIN) resulta em Count(select * from A) * Count(select * from B)linhas retornadas nesta consulta, em vez de apenas uma linha por tabela A, como o JOINretorno explícito (A<>B OR A=B). Isso claramente não é adequado. FIRSTnão parece estar disponível para uso dado um tipo de chave primária composta.

O segundo JOINestilo, embora indiscutivelmente mais legível, sofre por ser mais lento. Isso pode ocorrer porque dois JOINs internos adicionais são necessários contra a tabela maior, bem como os dois CROSS JOINs encontrados em ambas as opções.

Aparte: Substituir a IIFcláusula por MIN/ MAXparece retornar o mesmo número de entradas.
MAX(-(B.XTStamp<=A.RecTStamp)*B.XTStamp)
funciona para o timestamp "Antes" ( MAX), mas não funciona diretamente para o "Depois" ( MIN) da seguinte forma:
MIN(-(B.XTStamp>A.RecTStamp)*B.XTStamp)
porque o mínimo é sempre 0 para a FALSEcondição. Esse 0 é menor do que qualquer pós-época DOUBLE(do qual um DateTimecampo é um subconjunto no Access e no qual esse cálculo transforma o campo). Os métodos IIFe MIN/ MAXAs alternativas propostas para o valor AfterXTStamp funcionam porque a divisão por zero ( FALSE) gera valores nulos, que as funções de agregação MIN e MAX ignoram.

Próximos passos

Levando isso adiante, desejo encontrar os timestamps na segunda tabela que flanqueiam diretamente os timestamps na primeira tabela e realizar uma interpolação linear dos valores de dados da segunda tabela com base na distância de tempo para esses pontos (ou seja, se o timestamp de a primeira tabela está a 25% do caminho entre o "antes" e o "depois", gostaria que 25% do valor calculado viesse dos dados do valor da 2ª tabela associados ao ponto "depois" e 75% do "antes" ). Usando o tipo de junção revisado como parte das entranhas internas, e após as respostas sugeridas abaixo, eu produzo ...

    SELECT
        AvgGPS.XmitID,
        StrDateIso8601Msec(AvgGPS.RecTStamp) AS RecTStamp_ms,
        -- StrDateIso8601MSec is a VBA function returning a TEXT string in yyyy-mm-dd hh:nn:ss.lll format
        AvgGPS.ReceivID,
        RD.Receiver_Location_Description,
        RD.Lat AS Receiver_Lat,
        RD.Lon AS Receiver_Lon,
        AvgGPS.Before_Lat * (1 - AvgGPS.AfterWeight) + AvgGPS.After_Lat * AvgGPS.AfterWeight AS Xmit_Lat,
        AvgGPS.Before_Lon * (1 - AvgGPS.AfterWeight) + AvgGPS.After_Lon * AvgGPS.AfterWeight AS Xmit_Lon,
        AvgGPS.RecTStamp AS RecTStamp_basic
    FROM ( SELECT 
        AfterTimestampID.RecTStamp,
        AfterTimestampID.XmitID,
        AfterTimestampID.ReceivID,
        GPSBefore.BeforeXTStamp, 
        GPSBefore.Latitude AS Before_Lat, 
        GPSBefore.Longitude AS Before_Lon,
        GPSAfter.AfterXTStamp, 
        GPSAfter.Latitude AS After_Lat, 
        GPSAfter.Longitude AS After_Lon,
        ( (AfterTimestampID.RecTStamp - GPSBefore.XTStamp) / (GPSAfter.XTStamp - GPSBefore.XTStamp) ) AS AfterWeight
        FROM (
            (SELECT 
                ReceiverRecord.RecTStamp, 
                ReceiverRecord.ReceivID, 
                ReceiverRecord.XmitID,
               (SELECT TOP 1 XmitGPS.X_ID FROM SecondTable as XmitGPS WHERE ReceiverRecord.RecTStamp < XmitGPS.XTStamp ORDER BY XmitGPS.X_ID) AS AfterXmit_ID
             FROM FirstTable AS ReceiverRecord 
             -- WHERE ReceiverRecord.XmitID IN (select XmitID from ValidXmitters)
             GROUP BY RecTStamp, ReceivID, XmitID
            ) AS AfterTimestampID INNER JOIN SecondTable AS GPSAfter ON AfterTimestampID.AfterXmit_ID = GPSAfter.X_ID
        ) INNER JOIN SecondTable AS GPSBefore ON AfterTimestampID.AfterXmit_ID = GPSBefore.X_ID + 1
    ) AS AvgGPS INNER JOIN ReceiverDetails AS RD ON (AvgGPS.ReceivID = RD.ReceivID) AND (AvgGPS.RecTStamp BETWEEN RD.Beginning AND RD.Ending)
    ORDER BY AvgGPS.RecTStamp, AvgGPS.ReceivID;

...que retorna 152928 registros, correspondendo (pelo menos aproximadamente) ao número final de registros esperados. O tempo de execução é provavelmente de 5 a 10 minutos no meu sistema i7-4790, 16 GB de RAM, sem SSD, Win 8.1 Pro.


Referência 1: o MS Access pode lidar com valores de tempo de milissegundos - realmente e arquivo de origem [08080011.txt]

join ms-access
  • 3 respostas
  • 685 Views

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