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 / 37277
Accepted
Roddles
Roddles
Asked: 2013-03-22 11:34:35 +0800 CST2013-03-22 11:34:35 +0800 CST 2013-03-22 11:34:35 +0800 CST

Melhor solução para corrigir o design do banco de dados com GUID como chave primária

  • 772

Estou atrás de alguma confirmação dessa ideia para consertar um banco de dados com desempenho ruim ou uma sugestão melhor, se alguém tiver uma. Sempre aberto a melhores sugestões.

Eu tenho um banco de dados muito grande (mais de 20 milhões de registros crescendo cerca de 1/2 milhão por dia) que está usando GUID como PK.

Um descuido da minha parte, mas o PK está agrupado no servidor SQL e está causando problemas de desempenho.

O motivo de um guid - esse banco de dados é parcialmente sincronizado com 150 outros bancos de dados, portanto, o PK precisava ser exclusivo. A sincronização não é gerenciada pelo SQL Server, mas há um processo personalizado criado que mantém os dados sincronizados para os requisitos do sistema - tudo com base nesse GUID.

Cada um dos 150 bancos de dados remotos não armazena os dados completos armazenados no banco de dados SQL central. eles armazenam apenas um subconjunto dos dados de que realmente precisam, e os dados exigidos não são exclusivos deles (10 dos 150 bancos de dados podem ter alguns dos mesmos registros de bancos de dados de outros sites, por exemplo - eles compartilham). Além disso - os dados são realmente gerados nos sites remotos - não no ponto central - daí a necessidade dos GUIDs.

O banco de dados central é usado não apenas para manter tudo sincronizado, mas as consultas de mais de 3.000 usuários serão executadas nesse banco de dados fragmentado muito grande. Isso já é um grande problema nos testes iniciais.

Felizmente, ainda não estamos ativos - então posso fazer alterações e colocar as coisas offline, se necessário, o que é pelo menos alguma coisa.

O desempenho dos bancos de dados remotos não é um problema - os subconjuntos de dados são muito pequenos e o banco de dados geralmente nunca fica acima de 1 GB de tamanho total. Os registros são alimentados de volta ao sistema principal regularmente e removidos dos BDs menores quando não são mais necessários.

O desempenho do banco de dados central, que é o guardião de todos os registros, é lamentável - devido a um GUID agrupado como chave primária para tantos registros. A fragmentação do índice está fora dos gráficos.

Então - meus pensamentos para corrigir o problema de desempenho é criar uma nova coluna - Unsigned BIGINT IDENTITY (1,1) e, em seguida, alterar o Clustered PK da coluna BIGINT da tabela.

Eu criaria um índice exclusivo não clusterizado no campo GUID, que era a chave primária.

Os 150 bancos de dados remotos menores não precisam saber sobre o novo PK no banco de dados Central SQL Server - ele será usado exclusivamente para organizar os dados no banco de dados e interromper o mau desempenho e a fragmentação.

Isso funcionaria e melhoraria o desempenho do banco de dados SQL central e evitaria o futuro inferno da fragmentação do índice (até certo ponto, é claro)? ou eu perdi algo muito importante aqui que vai pular e me morder e causar ainda mais dor?

sql-server primary-key
  • 4 4 respostas
  • 7555 Views

4 respostas

  • Voted
  1. Best Answer
    David T. Macknet
    2013-03-22T11:47:07+08:002013-03-22T11:47:07+08:00

    Você certamente NÃO precisa agrupar no GUID. Se você tiver algo que permita identificar exclusivamente registros diferentes desse GUID, sugiro que você procure criar um índice exclusivo nesse outro campo e tornar esse índice agrupado. Caso contrário, você está livre para agrupar em outros campos, mesmo usando índices não exclusivos. A abordagem que haveria para agrupar, no entanto, facilita a divisão de seus dados e a consulta - portanto, se você tiver um campo "região" ou algo assim, isso pode ser um candidato para seu esquema de agrupamento.

    O problema com a mudança para um BIGINTseria adições aos dados de outros bancos de dados e integração de seu banco de dados no armazenamento central. Se isso não for uma consideração - e nunca será - então, sim, BIGINTresolveria bem o problema de rebalanceamento do índice.

    Nos bastidores, se você não especificar um índice clusterizado, o SQL Server faz praticamente a mesma coisa: ele cria um campo de ID de linha e mapeia todos os outros índices para ele. Então, fazendo você mesmo, você está resolvendo da mesma forma que o SQL resolveria.

    • 8
  2. granadaCoder
    2013-03-22T13:05:04+08:002013-03-22T13:05:04+08:00

    Isso é uma tarefa difícil.

    Deixe-me sugerir uma abordagem intermediária.

    Eu estava tendo problemas com System.Guid.NewGuid() gerando guids aleatórios. (Eu estava permitindo que o cliente criasse seu próprio guid, em vez de depender do banco de dados para criar um sequenceid).

    Depois que mudei para um UuidCreateSequential no lado do cliente, meu desempenho ficou MUITO melhor, especialmente em INSERTs.

    Aqui está o voodoo do código do cliente DotNet. Tenho certeza que penhorei de algum lugar:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    
    
    namespace MyCompany.MyTechnology
    {
      public static class Guid
      {
    
    
        [DllImport("rpcrt4.dll", SetLastError = true)]
        static extern int UuidCreateSequential(out System.Guid guid);
    
    
        public static System.Guid NewGuid()
        {
          return CreateSequentialUUID();
        }
    
    
        public static System.Guid CreateSequentialUUID()
        {
          const int RPC_S_OK = 0;
          System.Guid g;
          int hr = UuidCreateSequential(out g);
          if (hr != RPC_S_OK)
            throw new ApplicationException("UuidCreateSequential failed: " + hr);
          return g;
        }
    
    
      }
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
    
        /*
    
    Original Reference for Code:
    http://www.pinvoke.net/default.aspx/rpcrt4/UuidCreateSequential.html
    
    
    */
    
    /*
    
    
    
    Text From URL above:
    
    UuidCreateSequential (rpcrt4)
    
    Type a page name and press Enter. You'll jump to the page if it exists, or you can create it if it doesn't.
    To create a page in a module other than rpcrt4, prefix the name with the module name and a period.
    . Summary
    Creates a new UUID 
    C# Signature:
    [DllImport("rpcrt4.dll", SetLastError=true)]
    static extern int UuidCreateSequential(out Guid guid);
    
    
    VB Signature:
    Declare Function UuidCreateSequential Lib "rpcrt4.dll" (ByRef id As Guid) As Integer
    
    
    User-Defined Types:
    None.
    
    Notes:
    Microsoft changed the UuidCreate function so it no longer uses the machine's MAC address as part of the UUID. Since CoCreateGuid calls UuidCreate to get its GUID, its output also changed. If you still like the GUIDs to be generated in sequential order (helpful for keeping a related group of GUIDs together in the system registry), you can use the UuidCreateSequential function.
    
    CoCreateGuid generates random-looking GUIDs like these:
    
    92E60A8A-2A99-4F53-9A71-AC69BD7E4D75
    BB88FD63-DAC2-4B15-8ADF-1D502E64B92F
    28F8800C-C804-4F0F-B6F1-24BFC4D4EE80
    EBD133A6-6CF3-4ADA-B723-A8177B70D268
    B10A35C0-F012-4EC1-9D24-3CC91D2B7122
    
    
    
    UuidCreateSequential generates sequential GUIDs like these:
    
    19F287B4-8830-11D9-8BFC-000CF1ADC5B7
    19F287B5-8830-11D9-8BFC-000CF1ADC5B7
    19F287B6-8830-11D9-8BFC-000CF1ADC5B7
    19F287B7-8830-11D9-8BFC-000CF1ADC5B7
    19F287B8-8830-11D9-8BFC-000CF1ADC5B7
    
    
    
    Here is a summary of the differences in the output of UuidCreateSequential:
    
    The last six bytes reveal your MAC address 
    Several GUIDs generated in a row are sequential 
    Tips & Tricks:
    Please add some!
    
    Sample Code in C#:
    static Guid UuidCreateSequential()
    {
       const int RPC_S_OK = 0;
       Guid g;
       int hr = UuidCreateSequential(out g);
       if (hr != RPC_S_OK)
         throw new ApplicationException
           ("UuidCreateSequential failed: " + hr);
       return g;
    }
    
    
    
    Sample Code in VB:
    Sub Main()
       Dim myId As Guid
       Dim code As Integer
       code = UuidCreateSequential(myId)
       If code <> 0 Then
         Console.WriteLine("UuidCreateSequential failed: {0}", code)
       Else
         Console.WriteLine(myId)
       End If
    End Sub
    
    
    
    
    */
    

    IDEIA ALTERNATIVA:

    Se o seu banco de dados principal e os bancos de dados remotos estiverem "vinculados" (como em sp_linkserver) ...... você poderá usar o banco de dados principal como o "gerador de uuid".

    Você não quer obter "um por um" de uuid, isso é muita tagarelice.

    Mas você pode pegar um conjunto de uuid's.

    Abaixo segue algum código:

    IF EXISTS (SELECT * FROM sys.objects WHERE object_id =
     OBJECT_ID(N'[dbo].[uspNewSequentialUUIDCreateRange]') AND type in (N'P',
     N'PC'))
    
     DROP PROCEDURE [dbo].[uspNewSequentialUUIDCreateRange]
    
     GO
    
    
    
     CREATE PROCEDURE [dbo].[uspNewSequentialUUIDCreateRange] (
    
     @newUUIDCount int --return
    
     )
    
     AS
    
     SET NOCOUNT ON
    
     declare @t table ( dummyid int , entryid int identity(1,1) , uuid
     uniqueidentifier default newsequentialid() )
    
     insert into @t ( dummyid ) select top (@newUUIDCount) 0 from dbo.sysobjects
     so with (nolock)
    
     select entryid , uuid from @t
    
     SET NOCOUNT OFF
    
     GO
    

    /*

    --START TEST
    
     set nocount ON
    
     Create Table #HolderTable (entryid int , uuid uniqueidentifier )
    
     declare @NewUUIDCount int
    
     select @NewUUIDCount = 20
    
     INSERT INTO #HolderTable EXEC dbo.uspNewSequentialUUIDCreateRange
     @NewUUIDCount
    
     select * from #HolderTable
    
     DROP Table #HolderTable
    
     --END TEST CODE
    

    */

    • 1
  3. Jimbo
    2013-03-22T12:31:05+08:002013-03-22T12:31:05+08:00

    Com base na sua descrição, vá com BIGINT. No entanto, o índice para GUID pode ser não exclusivo, pois os GUIDs devem ser globalmente exclusivos de qualquer maneira.

    • 0
  4. Borik
    2013-03-22T12:09:10+08:002013-03-22T12:09:10+08:00

    Se o GUID for armazenado corretamente como identificador único, não haverá problemas de desempenho ... e se você puder usar o GUID sequencial ainda melhor ...

    Também @mattytommo tem um bom ponto sobre 11,5 anos usando INT ...

    • -1

relate perguntas

  • Chaves primárias de caractere x número inteiro

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

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

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

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • 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

    Conceder acesso a todas as tabelas para um usuário

    • 5 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
    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
    pedrosanta Listar os privilégios do banco de dados usando o psql 2011-08-04 11:01:21 +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