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 / 250518
Accepted
Sebastien Diot
Sebastien Diot
Asked: 2019-10-09 02:00:45 +0800 CST2019-10-09 02:00:45 +0800 CST 2019-10-09 02:00:45 +0800 CST

Encontrar uma linha por chave primária, quando você não sabe em qual tabela ela está?

  • 772

Eu sou o DBA (não oficial) responsável por um OODBMS proprietário. A gerência quer que mudemos para o Postgres, para reduzir os custos de licença. O movimento deve ser progressivo, portanto, devemos manter a mesma estrutura de dados do OODBMS. Felizmente, com o suporte para ARRAYs e herança de tabelas, podemos literalmente criar um esquema idêntico no Postgres. Todas as tabelas usarão bigint como chave primária e todas (indiretamente) herdarão da mesma tabela base.

O maior problema é este: nossa chave bigint é (e deve ser) única em todas as tabelas, e devemos ser capazes de carregar rapidamente um conjunto de linhas, com base em sua chave primária, sem saber em qual tabela elas estão . As linhas serão espalhadas por toda e qualquer tabela. A principal preocupação aqui é a velocidade , em vez do uso de disco ou memória.

Expresso de forma diferente, o que precisamos é de um índice exclusivo em todas as tabelas. AFAIK, isso não é possível no Postgres. Qual é a opção "próxima melhor"? Estou aberto a qualquer solução, incluindo usar, ou talvez até codificar, alguma "extensão Postgres".

Para dar algumas dicas sobre o banco de dados real, estamos falando de 300 tabelas, 130 milhões de linhas e cerca de 300 GB de tamanho (tamanho OODBMS).

performance postgresql-performance
  • 1 1 respostas
  • 364 Views

1 respostas

  • Voted
  1. Best Answer
    a_horse_with_no_name
    2019-10-09T02:23:16+08:002019-10-09T02:23:16+08:00

    Todas as tabelas usarão bigint como chave primária e todas (indiretamente) herdarão da mesma tabela base

    Não tenho certeza se gosto disso "todas as tabelas herdam da tabela base", mas, considerando isso, parece factível com o Postgres:

    Para gerar a chave primária para todas as tabelas, crie uma sequência:

    create sequence one_for_all as bigint;
    

    Crie a tabela base usando essa sequência para gerar os valores:

    create table base (id integer primary key default nextval('one_for_all'));
    

    Observe que a chave primária não será aplicada para as tabelas filhas!

    Em seguida, crie as tabelas filhas:

    create table t1 (t1_data integer, primary key (id)) inherits (base);
    create table t2 (t2_data integer, primary key (id)) inherits (base);
    

    Se você agora inserir nas tabelas filhas, a sequência será usada para gerar o ID:

    insert into t1 (t1_data) values (100);
    insert into t2 (t2_data) values (200);
    

    Para descobrir em qual tabela uma linha está localizada, selecione na tabela base e inclua a tableoidcoluna que identifica a tabela real na qual a linha está localizada:

    select b.*, tableoid::regclass as actual_table
    from base b
    where id = 42;
    

    Você ainda precisará de outra consulta para retornar a linha completa da tabela filha.

    Exemplo online: https://dbfiddle.uk/?rdbms=postgres_11&fiddle=4305e86b996e7a94c24faed733257232


    Outra abordagem que não precisa de herança é gerar valores de ID que codificam o nome da tabela (shudder).

    Algo na linha:

    create sequence one_for_all as bigint;
    create table lookup (table_name text primary key, code serial unique);
    insert into lookup (table_name) values ('base'), ('t1'), ('t2');
    
    create function get_id(p_tablename text)
      returns bigint
    as
    $$
      select nextval('one_for_all') * 1000 + code
      from lookup
      where table_name = p_tablename;
    $$
    language sql;
    
    create function get_tablename(p_id bigint)
      returns text
    as
    $$
      select table_name
      from lookup
      where code = p_id % 1000;  
    $$
    language sql;
    

    Ao multiplicar o valor da sequência por 1000, temos essencialmente os 3 dígitos inferiores disponíveis para codificar um número único para cada tabela. Para poder pesquisar esses números, precisamos dessa tabela adicional.

    Observe que isso falhará miseravelmente se a tabela de pesquisa não contiver todas as tabelas!

    Então, em vez de usar nextval()use, a get_id()função:

    create table base (id integer primary key default get_id('base'));
    create table t1 (id integer primary key default get_id('t1'), some_value integer);
    create table t2 (id integer primary key default get_id('t2'), some_data text);
    

    Então você pode fazer:

    insert into t1 (some_value) values (42);
    insert into t2 (some_data) values ('foo');
    insert into t1 (some_value) values (117);
    insert into t2 (some_data) values ('bar');
    

    Assim, as linhas em t2 agora vão para os IDs 2003 e 4003. A função get_tablename()pode ser usada para recuperar o nome da tabela à qual um ID pertence:

    select get_tablename(2003);
    
    get_tablename
    -------------
    t2           
    

    Isso é certamente mais rápido em termos de procurar o nome da tabela e não carrega a bagagem de uma enorme árvore de herança. Portanto, em termos de desempenho, provavelmente é mais rápido. No entanto, tornar-se-á um pesadelo de manutenção.

    O preenchimento da tabela de pesquisa talvez possa ser feito por meio de acionadores de eventos sempre que uma tabela for criada ou descartada.


    Se você puder alterar seu aplicativo para oferecer suporte a chaves primárias varchar, em vez de bigint (e puder conviver com os requisitos de armazenamento um pouco mais altos), também poderá gerar o ID como uma string que simplesmente contém o nome da tabela:

    create function get_id(p_tablename text)
      returns text
    as
    $$
      select concat(nextval('one_for_all'), '_', p_tablename)
    $$
    language sql;
    

    No entanto, coisas como classificação e consultas de intervalo serão complicadas.

    • 5

relate perguntas

  • Existe um ganho de desempenho ao manipular dados com procedimentos armazenados em vez de alimentá-los em funções após a recuperação?

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

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

  • 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

    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