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 / 179926
Accepted
Randomize
Randomize
Asked: 2017-07-16 08:14:23 +0800 CST2017-07-16 08:14:23 +0800 CST 2017-07-16 08:14:23 +0800 CST

Melhor maneira de concatenar uma sequência de substituições de strings no Amazon RDS?

  • 772

Eu tenho uma concatenação de substituições de strings desta maneira:

CREATE OR REPLACE FUNCTION norm(t text) RETURNS text AS $$
        declare t1 text;
        declare t2 text;
        ...
        declare t10 text;
        BEGIN
            select replace (lower(t), ',', ' ') into t1;
            select regexp_replace (t1, '[^0-9a-z\s-]', '', 'g') into t2;
            ...
            select regexp_replace (t10, 'n?oise?.*', '', 'g') into t10;
            RETURN trim(t10);
        END;
$$ LANGUAGE plpgsql;

Atualmente conta com 10 operações diferentes e o número não para de crescer. Também tem o inconveniente de mudar de posição para transformações forçar a renomear variáveis.

Existe uma maneira melhor de gerenciar essa situação?

postgresql amazon-rds
  • 2 2 respostas
  • 645 Views

2 respostas

  • Voted
  1. Evan Carroll
    2017-07-17T00:44:02+08:002017-07-17T00:44:02+08:00

    Com plperlueRegexp::Assemble

    Depende do comprimento da string e do comprimento da entrada. Você pode criar um regexp totalmente otimizado, usando Regexp::Assemble do Perl e executá-lo com plperlu.

    O código abaixo armazena em cache o regex para toda a sessão, portanto, as chamadas subsequentes devem ser rápidas.

    CREATE OR REPLACE FUNCTION replace_from_all(text, text[])
    RETURNS TEXT
    AS $$
      use strict;
    
      my ( $text, $rearray ) = @_;
      my $re;
    
      my $allre = join '', @$rearray;
      if ( exists $_SHARED{$allre} ) {
        $re = $_SHARED{$allre};
      }
      else {
        require "Regexp/Assemble.pm";
        my $ra = Regexp::Assemble->new;
        $ra->add($_) for @$rearray;
        $re = $_SHARED{$allre} = $ra->re;
      }
    
      $text =~ s/$re//ge;
      return $text;
    $$
    LANGUAGE plperlu
    IMMUTABLE;
    

    Agora você pode chamá-lo com,

    SELECT replace_from_all('foobar', ARRAY['o', 'b'] );
    

    Alternativamente, você hardcore os regexes lá, mas se você for fazer isso, você também pode cortar Regexp::Assemblee colar um regex pré-compilado.

    Complperl

    CREATE OR REPLACE FUNCTION replace_from_all(text, text[])
    RETURNS TEXT
    AS $$
      use strict;
    
      my ( $text, $rearray ) = @_;
      my $regexes;
    
      my $allre = join '', @$rearray;
      if ( exists $_SHARED{$allre} ) {
        $regexes = $_SHARED{$allre};
      }
      else {
        $regexes = $_SHARED{$allre} = [map qr/$_/, @$rearray];
      }
    
      foreach my $re ( @$regexes ) {
        $text =~ s/$re//ge;
      }
      return $text;
    $$
    LANGUAGE plperl
    IMMUTABLE;
    

    Velocidade

    Para este exemplo, peguei os seguintes dados de amostra, que são 300.000 linhas

    CREATE TABLE foo
    AS
      SELECT t.x FROM generate_series(1,1e5)
      CROSS JOIN ( VALUES
        ('You don''t like diacriticals àèìòùáéíóú'),
        ('You do like noiseless numbers'),
        ('And whatever you like to try also, removing commas, , , ')
    ) AS t(x);
    

    Para comparação, a versão acima de @joanolo leva 8,04 segundos

    SELECT norm(x) FROM foo;
    

    Usando plperl com,

    SELECT replace_from_all(x, ARRAY['[^0-9a-z\s-]', 'n?oise?.*'])
    FROM foo;
    

    Leva 5,0 segundos.

    • 2
  2. Best Answer
    joanolo
    2017-07-16T08:57:18+08:002017-07-16T08:57:18+08:00

    Você pode se ajudar com uma replacementsmesa:

    CREATE TABLE replacements
    (
        execution_order INTEGER NOT NULL PRIMARY KEY,
        search_regexp TEXT NOT NULL CHECK (search_regexp > ''),
        replace_by TEXT NOT NULL,
        flags TEXT NOT NULL DEFAULT 'g'
    ) ;
    

    Que você preencheria com quantas substituições você precisasse realizar:

    INSERT INTO replacements
        (execution_order, search_regexp, replace_by, flags)
    VALUES
        (100, '[^0-9a-z\s-]', '', 'g'),
        (200, 'n?oise?.*', '', 'g') ;
    

    E então mude sua função para usá-la:

    CREATE OR REPLACE FUNCTION norm(t_in text) 
    RETURNS text AS 
    
    $body$
    DECLARE
        t_out text ;
        rep record ;
    BEGIN
        t_out := replace(lower(t_in), ',', ' ') ;
        FOR rep IN
            SELECT search_regexp, replace_by, flags
            FROM replacements
            ORDER BY execution_order
        LOOP
            t_out := regexp_replace(t_out, rep.search_regexp, rep.replace_by, rep.flags) ;
        END LOOP ;
        RETURN t_out ;
    END ;
    $body$ 
    
    LANGUAGE plpgsql IMMUTABLE STRICT ;
    

    E confira os resultados:

    SELECT
        norm('You don''t like diacriticals àèìòùáéíóú') AS n1,
        norm('You do like noiseless numbers') AS n2,
        norm('And whatever you like to try also, removing commas, , , ') AS n3;
    
    n1 | n2 | n3                                                      
    :-------------------------- | :----------- | :------------------------------------------------- ------
    você não gosta de diacríticos | você gosta | e o que você quiser, tente também remover vírgulas      
    

    Isso não será tão rápido quanto codificar todas as alterações em sua função, mas permitirá maior flexibilidade.


    Como alternativa, você pode simplesmente alterar a estrutura de código da sua função e reutilizar a mesma variável mais de uma vez 1 :

    CREATE OR REPLACE FUNCTION norm(t_in text) 
    RETURNS text AS 
    
    $body$
    DECLARE
        t_out text ;
    BEGIN
        t_out := replace(lower(t_in), ',', ' ') ;
        t_out := regexp_replace(t_out, '[^0-9a-z\s-]', '', 'g') ;
        t_out := regexp_replace(t_out, 'n?oise?.*', '', 'g') ;
        -- Keep adding substitutions, or inserting them where appropriate
        RETURN t_out ;
    END ;
    $body$ 
    
    LANGUAGE plpgsql IMMUTABLE STRICT ;
    

    Isso é mais rápido e a melhor alternativa se o número de substituições for moderado.

    Você pode verificá-lo no dbfiddle aqui


    1) PLPGSQL não é uma linguagem funcional que obriga você a atribuir apenas uma vez a vals, as variáveis ​​podem ser sobrescritas quantas vezes forem necessárias. Se você pensar em termos de Scala , eles são vars, não vals. Em termos de Java, eles não são immutable.

    • 1

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

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

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

  • 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