consideração o desempenho: linhas de spread em várias tabelas vs concentrado todas as linhas em uma tabela

StackOverflow https://stackoverflow.com/questions/1142296

Pergunta

consideração de desempenho: linhas de spread em várias tabelas vs concentrado todas as linhas em uma tabela

.

Hi.

Eu preciso registrar informações sobre sobre cada passo que se passa no aplicativo em um SQL DB. Há certas tabelas, eu quero o log deve estar relacionado com: Do produto - deve registrar quando um produto foi criado mudou etc. Fim - mesmo que acima Transporte - mesmo etc etc etc.

Os dados serão necessidade de ser recuperada muitas vezes.

Eu tenho algumas idéias sobre como fazê-lo:

  1. Tenha uma tabela log que conterá colunas para todas essas tabelas, então quando eu quero representar dados na interface do usuário para um determinado produto irá fazer select * from Log onde LogId = Product.ProductId. Eu sei que isso pode ser engraçado ter muitas cols, mas eu tenho essa sensação de que o desempenho será melhor. Por outro lado, haverá uma enorme quantidade de linhas na tabela.
  2. têm muitas mesas de registro para cada tipo de log (ProductLogs, OrderLogs etc.) Eu realmente não gosto dessa idéia, pois não é consistente e tem muitas tabelas com mesma estrutura não faz sentido, mas (?) Pode ser mais rápido ao pesquisar em uma tabela que tem uma menor quantidade de linhas (errado mi?).
  3. De acordo com a declaração não. 1, eu poderia fazer uma segunda tabela-to-one muitos que terá LogId, TableNameId e RowId cols, e irá referenciar uma linha de log para muitas linhas de tabela no DB, que terá um UDF para recuperar dados (por exemplo, ID de log 234 pertence à mesa ao Cliente no CustomerId 345 e para a tabela Produtos onde productId = RowId); Penso que esta é a melhor maneira de fazê-lo, mas, novamente, pode haver uma enorme quantidade de linhas, vai desacelerar a pesquisa? ou é assim que deve ser feito, o que você diria? ...

Exemplo de No. 3 na lista acima:

CREATE TABLE [dbo].[Log](
    [LogId] [int] IDENTITY(1,1) NOT NULL,
    [UserId] [int] NULL,
    [Description] [varchar](1024) NOT NULL,
 CONSTRAINT [PK_Log] PRIMARY KEY CLUSTERED 
(
    [LogId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
ALTER TABLE [dbo].[Log]  WITH CHECK ADD  CONSTRAINT [FK_Log_Table] FOREIGN KEY([UserId])
REFERENCES [dbo].[Table] ([TableId])
GO
ALTER TABLE [dbo].[Log] CHECK CONSTRAINT [FK_Log_Table]
---------------------------------------------------------------------
CREATE TABLE [dbo].[LogReference](
    [LogId] [int] NOT NULL,
    [TableName] [varchar](32) NOT NULL,
    [RowId] [int] NOT NULL,
 CONSTRAINT [PK_LogReference] PRIMARY KEY CLUSTERED 
(
    [LogId] ASC,
    [TableName] ASC,
    [RowId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[LogReference]  WITH CHECK ADD  CONSTRAINT [FK_LogReference_Log] FOREIGN KEY([LogId])
REFERENCES [dbo].[Log] ([LogId])
GO
ALTER TABLE [dbo].[LogReference] CHECK CONSTRAINT [FK_LogReference_Log]
---------------------------------------------------------------------
CREATE FUNCTION GetLog
(   
    @TableName varchar(32),
    @RowId int
)
RETURNS 
@Log TABLE
(       
    LogId int not null,
    UserId int not null,
    Description varchar(1024) not null
)
AS
BEGIN

INSERT INTO @Log
SELECT     [Log].LogId, [Log].UserId, [Log].Description
FROM         [Log] INNER JOIN
                      LogReference ON [Log].LogId = LogReference.LogId
WHERE     (LogReference.TableName = @TableName) AND (LogReference.RowId = @RowId)
    RETURN 
END
GO
Foi útil?

Solução

Eu definitivamente ir para a opção 3, por várias razões:

Os dados devem estar nos campos de uma tabela, não como um nome de tabela (opção 2) ou um nome de campo (opção 1). Dessa forma, o banco de dados fica mais fácil de trabalhar e mais fácil de manter.

mesas mais estreitos genrally um melhor desempenho. O número de linhas tem menos impacto sobre o desempenho do que o número de campos.

Se você tem um campo para cada tabela (opção 1), que são susceptíveis de ter um monte de campos vazios quando apenas algumas das mesas são afetados por uma operação.

Outras dicas

Tenha cuidado com preoptimizing bancos de dados. A maioria dos bancos de dados são razoavelmente rápido e um pouco complicado. Você deseja executar um teste para a eficiência em primeiro lugar.

Segundo colocar tudo em uma tabela faz com que seja mais provável que os resultados desejados são no cache que irá acelerar o desempenho imensamente. Infelizmente, ele também torna muito mais provável que você vai ter que procurar uma mesa gigantesca para encontrar o que está procurando. Isto pode ser parcialmente resolvido com um índice, mas os índices não são gratuitos (que tornar a escrita mais caro, para um).

Meu conselho seria para fazer um teste para ver se o desempenho realmente importa e testar os diferentes cenários para ver qual é o mais rápido.

Se você está falando de grandes volumes de dados (milhões de linhas +), então você vai ter ter um benefício de usar tabelas diferentes para armazená-los em.

por exemplo. Exemplo 50 milhões de entradas de registo de base, assumindo 5 "tipos" diferentes de tabela de log Melhor ter 5 x 10 milhões mesas linha de 1 x 50000000 linha da tabela

  • desempenho INSERIR será melhor com tabelas individuais - índices em cada tabela será menor e de modo mais rápido / mais fácil de ser atualizado / mantida como parte da operação de inserção

  • desempenho LEIA será melhor com tabelas individuais - menos dados para consulta, índices menores para atravessar. Além disso, parece que você precisaria para armazenar uma coluna extra para identificar que tipo de entrada do Registro de um registro é (produto, transporte ....)

  • MANUTENÇÃO em mesas menores é menos doloroso (estatísticas, o índice de desfragmentação / reconstrução etc)

Essencialmente, trata-se de particionamento de dados. De SQL 2005 em diante, ele tem suporte embutido para particionar (veja aqui ), mas você precisa Enterprise Edition para isso, que basicamente permite que você partição de dados de uma tabela para melhorar o desempenho (por exemplo, você teria o seu uma tabela log e, em seguida, definir a forma como os dados dentro dele é particionado)

Eu escutei uma entrevista com um dos arquitetos do eBay recentemente, que destacou a importância de particionamento quando precisar de desempenho e escalabilidade e concordo fortemente baseado em minhas experiências.

Tente implementar sua camada de acesso a dados de uma forma para que você possa mudar de um modelo de banco de dados para outro, se necessário -. Dessa forma, você apenas escolher um e preocupação sobre as implicações de desempenho mais tarde

Sem fazer alguns testes de desempenho e ter uma idéia precisa dos tipos de carga seu curso para obter a sua vai ser difícil otimizar como o desempenho depende de uma série de fatores, tais como o número de leituras, o número de gravações e se ou não o lê e escreve são susceptíveis de conflito e causar bloqueio.

A minha preferência seria para a opção 1 btw -. Sua forma mais simples de fazer e há uma série de ajustes que você pode fazer para ajudar a corrigir vários tipos de problemas que você pode ter

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top