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 / 311171
Accepted
Thomas
Thomas
Asked: 2022-04-21 12:15:52 +0800 CST2022-04-21 12:15:52 +0800 CST 2022-04-21 12:15:52 +0800 CST

Mais colunas versus mais linhas para otimizar o armazenamento e o desempenho?

  • 772

Tenho uma tabela com esta estrutura:

ticker         VARCHAR                     NOT NULL,
interval       VARCHAR                     NOT NULL,
ts             TIMESTAMP WITHOUT TIME ZONE NOT NULL,
price          FLOAT8                      NOT NULL,
UNIQUE (ticker, interval, ts)

Existem 40 tickers (que eventualmente serão estendidos para cerca de 130) e 8 intervalos. Novas linhas (40 * 8) são adicionadas a cada 10 segundos como uma cópia em massa, o que representa 115 mil linhas/hora. Eles são escritos uma vez e nunca modificados.

As operações de leitura são sempre feitas para intervalos de tempo bastante grandes (vários dias) e solicitam um ticker e 3 intervalos para ele, usando isto:

SELECT * FROM exchange.{tableName}
WHERE ticker = '{ticker}' AND \"interval\" IN ({intervalsText})
AND ts >= '{fromTime.Format}' AND ts < '{toTime.Format}'
ORDER BY ts

Minha pergunta aqui é se seria benéfico agrupar todos os intervalos em uma única linha por ticker. Assim:

ticker           VARCHAR                     NOT NULL,
ts               TIMESTAMP WITHOUT TIME ZONE NOT NULL,
price_interval0  FLOAT8                      NOT NULL,
price_interval1  FLOAT8                      NOT NULL,
...
price_interval7  FLOAT8                      NOT NULL,
UNIQUE (ticker, ts)

Isso significa 8x menos linhas na tabela, um índice menor, mas cada consulta pode precisar carregar a linha inteira para retornar apenas 3 valores e descartar 5.

Eu não sei como o Postgres organiza os dados internamente e se uma linha inteira seria recuperada de uma só vez (que é minha suposição) e então partes dela seriam extraídas, etc ...

Qualquer conselho seria muito apreciado.

database-design postgresql
  • 1 1 respostas
  • 223 Views

1 respostas

  • Voted
  1. Best Answer
    Erwin Brandstetter
    2022-04-21T14:16:10+08:002022-04-21T14:16:10+08:00

    Com o tempo, isso vai ser um monte de linhas!

    Fundamentos

    Sim, armazenar 8 float8em uma única linha superará 8 linhas com 1 float8cada uma por um tiro longo, em armazenamento e desempenho.
    Mas você pode fazer mais...

    Design de mesa

    Para otimizar o armazenamento e o desempenho :

    CREATE TABLE ticker (
      ticker_id smallint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
    , ticker text NOT NULL UNIQUE   
    );
    
    CREATE TABLE tbl (
      the_date        date     NOT NULL  -- columns in this order!
    , timeslot        smallint NOT NULL
    , ticker_id       smallint NOT NULL REFERENCES ticker
    , price_interval0 int      NOT NULL
    , price_interval1 int      NOT NULL
     ...
    , price_interval7 int      NOT NULL
    CONSTRAINT tbl_pkey PRIMARY KEY (ticker_id, the_date, timeslot);  -- columns in this order!
    );
    

    db<>fiddle aqui - incluindo todos

    Explicação e auxiliares

    Uma entrada a cada 10 segundos chega a 6*60*24 = 8640 intervalos de tempo distintos por dia. A smallintcom seu intervalo de -2^15 a 2^15 pode facilmente manter isso.

    É claro que não armazenamos o nome completo do ticker todas as vezes. Uma coluna FK smallint cobre facilmente 40 - 130 tickers distintos e faz referência a uma tickertabela. Normalmente melhor para armazenamento e desempenho:

    • Índices: desempenho inteiro vs string se o número de nós for o mesmo

    O dia como date(4 bytes), um intervalo de tempo smallint(2 bytes) e um smallintpara o ID do ticker, dispostos nesta sequência ocupam 8 bytes sem preenchimento de alinhamento!
    Infelizmente, não podemos otimizar o índice PK perfeitamente ao mesmo tempo e incorrer em 8 bytes de preenchimento de alinhamento. A única mancha na otimização de armazenamento.

    Por conveniência, você pode adicionar um VIEWpara obter dados bonitos:

    CREATE VIEW tbl_pretty AS
    SELECT ti.ticker, the_date + interval '10 sec' * timeslot AS ts, price_interval0, price_interval1
    --   , price_interval2, ...
    FROM   tbl
    JOIN   ticker ti USING (ticker_id);
    

    Como você pode ver, essa expressão produz seu carimbo de data/hora original:

    the_date + interval '10 sec' * timeslot
    

    A conversão reversa será usada na consulta abaixo:

    trunc(EXTRACT(EPOCH FROM time '12:34:56'))::int / 10)
    

    Valores monetários como um "preço" não devem ser armazenados como número de ponto flutuante. Isso é uma arma de pé carregada. Usar numeric. Ou, como estamos otimizando para armazenamento e desempenho, uma integerrepresentação de Cents normalmente funciona melhor. E isso é apenas 4 bytes em vez de 8 bytes para float8. ( numericdepende do comprimento real, normalmente maior). Ver:

    • É possível inserir dados não formatados para o tipo de dados dinheiro no PostgreSQL

    • PostgreSQL: Qual tipo de dados deve ser usado para moeda?

    Armazenar

    Isso vai ocupar:

    • (24(cabeçalho da tupla) + 4(identificador do item) + 4 + 2 + 2 + 4*8 + 4) = 72 bytes por linha da tabela - sem preenchimento
      (Sua ideia original para a linha composta ocuparia (24 + 4 + (min. 8) + 8 + 8*8) = 108 bytes ou mais por linha.)
    • (8(cabeçalho de índice) + 2 + 2(preenchimento) + 4 + 2 + 6(preenchimento)) = 24 bytes por entrada de índice PK

    Além de sobrecarga mínima por página de dados de 8kb e nenhuma sobrecarga para tuplas mortas (nunca atualizadas).

    Detalhes:

    • Entendendo os tamanhos de linha do Postgres
    • Calculando e economizando espaço no PostgreSQL
    • Configurando o PostgreSQL para desempenho de leitura

    O índice PK seria menor (16 em vez de 24 bytes por tupla) se pudéssemos fazê-lo em (the_date, timeslot, ticker_id). Mas precisamos dele para (ticker_id, the_date, timeslot)dar suporte à sua consulta de maneira ideal. Igualdade antes do intervalo . Ver:

    • Um índice composto também é bom para consultas no primeiro campo?
    • Índice e desempenho de várias colunas

    Consulta

    Sua consulta se torna:

    SELECT price_interval3, price_interval7  -- just the intervals you need
    FROM   tbl
    WHERE  ticker_id = (SELECT ticker_id FROM ticker WHERE ticker = 'ticker_3')
    AND    (the_date, timeslot) >= (date '2022-04-20', trunc(EXTRACT(EPOCH FROM time '00:00:00'))::int / 10)
    AND    (the_date, timeslot) <  (date '2022-04-20', trunc(EXTRACT(EPOCH FROM time '00:01:00'))::int / 10)
    ORDER  BY the_date, timeslot;
    

    Ou curta:

    SELECT *
    FROM   tbl
    WHERE  ticker_id = 3
    AND    (the_date, timeslot) >= ('2022-04-20', 0)
    AND    (the_date, timeslot) <  ('2022-04-20', 6)
    ORDER  BY the_date, timeslot;
    

    Observe o uso da comparação de valores ROW! Ver:

    • Termo de sintaxe SQL para 'WHERE (col1, col2) < (val1, val2)'
    • Qual é uma boa maneira de fazer uma comparação > ou < que considera NULLs ordenados primeiro ou por último?

    atuação

    Isso é perfeitamente suportado pelo índice PK no (ticker_id, the_date, timeslot). Nenhum outro índice necessário. Você recebe um plano como:

    Index Scan using tbl_pkey on tbl  (cost=0.27..8.29 rows=1 width=16)
      Index Cond: ((ticker_id = 3) AND (ROW(the_date, timeslot) >= ROW('2022-04-20'::date, 0)) AND (ROW(the_date, timeslot) < ROW('2022-04-20'::date, 6)))
    
    • 2

relate perguntas

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Quais são algumas maneiras de implementar um relacionamento muitos-para-muitos em um data warehouse?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

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