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 / 204545
Accepted
Jersey
Jersey
Asked: 2018-04-21 08:30:33 +0800 CST2018-04-21 08:30:33 +0800 CST 2018-04-21 08:30:33 +0800 CST

Criando uma coluna computada persistente com uma função

  • 772

Estou trabalhando com os programadores em uma solução de banco de dados. Eles querem adicionar uma coluna computada para imitar as chaves antigas para as consultas, procedimentos e sistemas mais antigos e indexá-la. As novas chaves serão GUIDS.

Para fazer isso, eles desejam criar uma função para a coluna computada que cria um valor e o mantém. Não vai deixá-los persistir na coluna. Eu não tenho nenhuma curiosidade sobre a ideia e também não consigo encontrar nenhuma informação na web sobre a técnica (é uma técnica?).

Estou pensando que eles precisam adicionar um gatilho em vez disso. Alguém tem alguma idéia?

A função será executada assim:

(SELECT [INT Identity field] FROM TABLE WHERE [GUID COLUMN] = @GUIDKEY

Ele retorna um campo INT Identity baseado no GUID.

Isso será executado em cada inserção em uma tabela relacionada. Portanto, se a Tabela Um tiver a chave primária, a tabela relacionada Dois será atualizada (usando o GUID passado) para obter a chave da Tabela um e inseri-la na tabela dois.

sql-server sql-server-2008
  • 5 5 respostas
  • 5667 Views

5 respostas

  • Voted
  1. Best Answer
    Aaron Bertrand
    2018-04-21T10:22:09+08:002018-04-21T10:22:09+08:00

    Ainda não entendo por que isso precisa ser uma coluna em uma tabela , muito menos uma persistente.

    Por que não apenas criar uma função com valor de tabela que você aplica quando (e somente quando) a consulta realmente precisa dela? Como a chave antiga nunca será alterada, ela não precisa ser computada ou persistida de qualquer maneira.

    Se você realmente deseja que a chave antiga viva em vários lugares (e parece que as pessoas que não deveriam tomar esse tipo de decisão já tomaram esse tipo de decisão), basta fazer a pesquisa em um gatilho e preenchê-lo no momento da gravação . Então é apenas uma coluna estática em uma tabela.

    Eu ainda recomendo uma função com valor de tabela para facilitar isso, para que você possa escrever o gatilho de forma que ele lide com operações de várias linhas ... sem ter que escrever um loop ou chamar uma função de valor escalar sobre e novamente para cada linha.

    Apenas para mostrar como essas coisas realmente são semelhantes (e questione seu desenvolvedor líder que "não gosta disso"):

    -- bad, slow, painful row-by-row
    CREATE FUNCTION dbo.GetIDByGUID
    (
      @GuidKey uniqueidentifier
    )
    RETURNS int
    AS
    BEGIN
      RETURN (SELECT $IDENTITY FROM dbo.tablename WHERE guid_column = @GuidKey);
    END
    GO
    
    -- in the trigger:
    UPDATE r SET oldkey = dbo.GetIDByGUID(i.guid_column)
      FROM dbo.related AS r
      INNER JOIN inserted AS i
      ON r.guid_column = i.guid_column;
    

    Agora, se você tiver uma função com valor de tabela, o código é bastante semelhante, mas você descobrirá que o desempenho é muito melhor em operações de várias linhas e quase idêntico para operações de uma única linha.

    -- ah, much better
    ALTER FUNCTION dbo.GetIDByGUID_TVF
    (
      @GuidKey uniqueidentifier
    )
    RETURNS TABLE
    AS
      RETURN (SELECT id = $IDENTITY FROM dbo.tablename WHERE guid_column = @GuidKey);
    GO
    
    -- in the trigger:
    UPDATE r SET oldkey = f.id
      FROM dbo.related AS r
      INNER JOIN inserted AS i
      ON r.guid_column = i.guid_column
      CROSS APPLY dbo.GetIDByGUID_TVF(i.guid_column) AS f;
    
    • 9
  2. Erik Darling
    2018-04-21T08:53:27+08:002018-04-21T08:53:27+08:00

    Não sei por que você acha que precisa de uma função ou de uma coluna computada para fazer isso. Você pode simplesmente adicionar uma nova coluna à tabela com um valor padrão e indexá-la como quiser.

    CREATE TABLE dbo.whatever ( Id INT );
    
    ALTER TABLE dbo.whatever
    ADD YourMom UNIQUEIDENTIFIER
            DEFAULT NEWSEQUENTIALID();
    
    CREATE INDEX ix_whatever ON dbo.whatever (YourMom);
    

    Já que você atualizou sua pergunta, vamos abordar que ideia realmente horrível é essa. Vou simplificar um pouco o exemplo.

    CREATE TABLE dbo.whatever ( Id INT PRIMARY KEY);
    
    CREATE TABLE dbo.ennui ( Id INT PRIMARY KEY, meh INT );
    GO 
    
    CREATE FUNCTION dbo.BadIdea ( @notguido INT )
    RETURNS INT
    WITH SCHEMABINDING, RETURNS NULL ON NULL INPUT
    AS
        BEGIN
            DECLARE @out INT;
            SELECT @out = ( SELECT e.Id FROM dbo.ennui AS e WHERE e.meh = @notguido );
            RETURN @out;
        END;
    GO 
    
    ALTER TABLE dbo.whatever ADD ishygddt AS dbo.BadIdea(Id)
    
    /*Will fail*/
    ALTER TABLE dbo.whatever ALTER COLUMN ishygddt ADD PERSISTED;
    
    /*Will fail*/
    CREATE INDEX ix_whatever ON dbo.whatever (ishygddt);
    

    Tentar persistir uma coluna computada com base em uma função escalar (mesmo uma determinística com SCHEMABINDING ) falhará se eles realizarem acesso a dados.

    Msg 4934, Nível 16, Estado 3, Linha 23 A coluna computada 'ishygddt' na tabela 'whatever' não pode ser mantida porque a coluna faz acesso a dados do usuário ou do sistema.

    Nem você pode indexá-lo:

    Msg 2709, Level 16, State 1, Line 25 A coluna 'ishygddt' na tabela 'dbo.whatever' não pode ser usada em um índice ou estatística ou como uma chave de partição porque faz acesso a dados do usuário ou do sistema.

    Você também terá muitos problemas porque a função executará linha por linha para recuperar dados e forçará todas as consultas na tabela a serem executadas em série .

    Se você estiver modificando dados na tabela que a função faz referência e selecionando dados da tabela que chama a função na coluna computada, você pode acabar com alguns cenários de bloqueio realmente confusos em que a função é impedida de retornar dados para uma consulta em uma tabela aparentemente não relacionada.

    Esta é uma má idéia ao redor. Aaron deu o que eu acho que é o melhor conselho em seu comentário:

    Por que não apenas criar uma função com valor de tabela que você aplica quando (e somente quando) a consulta realmente precisa dela? Como a chave antiga nunca será alterada, ela não precisa ser computada ou persistida de qualquer maneira. Se você realmente deseja que a chave antiga resida em vários lugares, basta fazer a pesquisa em um gatilho.

    • 8
  3. David Browne - Microsoft
    2018-04-21T08:48:05+08:002018-04-21T08:48:05+08:00

    Você pode ler sobre Colunas Computadas Persistentes em BOL e os Índices relacionados em Colunas Computadas .

    Há restrições na expressão que você pode usar em uma coluna computada persistente. A expressão "deve ser determinística quando PERSISTED for especificado."

    • 5
  4. Shannon Severance
    2018-04-21T16:10:36+08:002018-04-21T16:10:36+08:00

    Se bem entendi, você tem:

    1. Uma mesa, vamos chamá-la t.
    2. A tabela ttem uma coluna guid, vamos chamá-la de gc.
    3. Uma tabela adicional é uma pesquisa que mapeia os valores t.gcpara um valor de chave diferente de um tipo diferente, que é usado no código herdado. Vamos chamar a tabela lte a coluna de chave herdada lk.
    4. Você deseja lt.lkaparecer tcomo t.lkcódigo legado que pode continuar usando-o.

    Eu investigaria usando uma visão.

    1. Renomeie t, para algo como t_base.
    2. Crie uma exibição chamada tque une e retorna t_basea ltcoluna de t_basee lt.lk.
    3. Se for necessário persistir, investigue as exibições indexadas. (Requer edição empresarial e tem muitas restrições, mas provavelmente apropriado para esta junção.)
    • 1
  5. jpmc26
    2018-05-14T01:37:41+08:002018-05-14T01:37:41+08:00

    O problema real

    O problema que os desenvolvedores estão tentando resolver é um problema de migração bastante padrão, de um tipo de dados para um novo. Eles têm um novo problema que não foi previsto no momento em que o banco de dados foi originalmente projetado; ou seja, eles agora precisam sincronizar dados entre bancos de dados. Isso tende a ser um esforço caro, principalmente se os tipos de dados forem utilizados em muitos códigos. Procurar medidas de redução de custos não é totalmente irracional.

    A solução deles

    A matemática diz que não

    Em primeiro lugar, é importante perceber que o problema é provavelmente matematicamente intratável. Um GUID ou UUID é apenas um número de 128 bits ou 16 bytes. O tamanho de uma IDENTITYcoluna depende do tipo de dados usado, mas normalmente são INT(32 bits, 4 bytes); às vezes BIGINT(64 bits, 8 bytes) é usado. Não há uma maneira matemática de mapear totalmente o intervalo de GUIDs para o intervalo de INTs ou mesmo BIGINTs. É matematicamente possível se a coluna for DECIMAL(38,0), que é grande o suficiente, mas isso é altamente incomum.

    Praticidade

    Mesmo que seja possível mapear GUIDs para o DECIMALtipo, isso não significa que seja prático. Praticamente ninguém faz isso, então você terá que gastar tempo (=dinheiro) garantindo que o mapeamento funcione corretamente. Sua solução apresenta um risco não insignificante de criar bugs estranhos e difíceis de diagnosticar.

    Além disso, você não preservará os IDs existentes dos dados com sua solução. Isso pode quebrar quaisquer marcadores que os usuários finais tenham que incluam os IDs.

    Finalmente, sua solução provavelmente estará enraizada . Não é uma boa prática por causa de todos os motivos acima, mas se eles conseguirem, é provável que eles não trabalhem para se afastar dele tão cedo porque é muito "fácil" continuar usando as chaves inteiras em todos os novos código.

    Uma abordagem mais padrão

    Uma abordagem relativamente padrão para introduzir a sincronização em um sistema existente é adicionar um novo ID exclusivo . Esse novo ID é colocado nos dados , além das chaves antigas existentes. Então as chaves substitutas não são sincronizadas.

    Isso tem alguns benefícios importantes:

    • Resolve o problema de habilitar a sincronização entre bancos de dados.
    • O código existente que depende das chaves antigas não precisa ser alterado. (Definitivamente não no curto prazo, e possivelmente nunca.)
    • Sem mapeamentos matematicamente impossíveis.
    • Os valores de chave existentes são preservados.

    Há dois pequenos aborrecimentos com essa abordagem:

    • Como as chaves substitutas não são sincronizadas, se as chaves substitutas aparecerem no código e principalmente no aplicativo, esses IDs serão diferentes em diferentes bancos de dados. Para sua situação específica (sincronização com cópias de teste e desenvolvimento do banco de dados, em vez de algum tipo de replicação em vários bancos de dados de produção), isso é apenas um pequeno aborrecimento. No entanto, também é algo que pode ser resolvido: à medida que a necessidade se torna mais aparente por meio de quaisquer ineficiências que isso crie, os desenvolvedores podem ajustar partes de código específicas e direcionadas para usar o novo ID de sincronização conforme necessário, sem reescrever todo o aplicativo. Eles podem até oferecer suporte a ambos os IDs por um tempo. (Por exemplo, um ponto de extremidade da Web pode aceitar uma chave inteira e redirecionar para a chave GUID para garantir que os indicadores não sejam quebrados.) Isso também se torna o motivo para migrar lentamente do uso das chaves inteiras no código.
    • O código de sincronização pode ter que mapear IDs substitutos inteiros ao sincronizar dados com uma chave estrangeira. Isso está longe de ser um problema intratável, no entanto. Basta procurar o ID de sincronização relacionado e usá-lo para localizar a chave substituta de inteiro do banco de dados de destino. No entanto, parece que sua equipe de desenvolvimento já está preparada para mudar as chaves estrangeiras das chaves substitutas existentes para as novas chaves GUID, então isso pode não ser um problema.

    Ambos os problemas são gerenciáveis, porém, e são compensações razoáveis ​​a serem feitas se mudar tudo para GUIDs agora for muito caro.

    Também vale a pena notar que esta solução permitiu exatamente a consulta que eles estão pedindo para poder fazer.

    Isso pode ser tarde demais para ajudá-lo agora, mas acho que é uma boa informação daqui para frente.

    • 1

relate perguntas

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Quanto "Padding" coloco em meus índices?

  • Existe um processo do tipo "práticas recomendadas" para os desenvolvedores seguirem para alterações no banco de dados?

  • 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

    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