Isenção de responsabilidade
Eu tive uma ideia para um design de mesa há pouco tempo que fez sentido para mim na época. Na história recente, percebi que tenho o hábito de "engenharia em excesso" ou gastar muito tempo tentando "otimizar demais" as soluções. Estou assumindo que este é um daqueles casos em que estou pensando demais na solução e criarei uma sobrecarga extra com pouco ou nenhum ganho real.
Pergunta
Suponha que para um objeto (um Shipment
table
por exemplo) existe algum tipo de NOTE
varchar(MAX)
elemento de dados que queremos acompanhar. O NOTE
column
tem a oportunidade de ter dados empurrados para um estouro e aumentar drasticamente o tamanho do row
(limitando assim o número rows
que pode ser salvo no page
). Pelo que entendi, isso impacta negativamente no tempo de execução de várias operações na tabela como um todo.
Existe algum caso em que devemos empurrar isso column
para um stand separado sozinho ShipmentNote
table
em vez de mantê-lo como column
um Shipment
table
? A teoria é que, se empurrarmos o NOTE
column
para um separado table
, ele salva o pages
on the, o Shipment
table
que permite que todas as operações no the Shipment
table
tenham um desempenho melhor. Porque o row
tamanho é menor e agora você pode caber mais rows
no mesmo page
.
(Veja exemplos de esquema abaixo):
O principal caso de uso em que isso pode ser uma boa ideia é se:
- O
Note
column
é regularmente mais de 8000 caracteres (o que eu acho que é quando começamos a usar a paginação extra) - O
Note
column
único retornado emSELECT
operações e raramente ou nunca é usado como parte de umJOIN
ouWHERE
- O restante será consultado independentemente de
columns
forma regular (IE: a maioria de nossas operações, não utilizará , seja isso ou condições acontecendo em outros em `Remessa)Shipment
Note
Note
JOIN
WHERE
columns
As desvantagens que estou vendo (fora disso, podem não fazer melhorias perceptíveis no trabalho com a Shipment
tabela fora da Note
coluna):
- Agora se torna impossível (ou pelo menos requer um
trigger
ou outra coisa) garantir que sempre haja algum tipo de valor paraNOTE
(IE: porque agora está em um separadochild table
, não podemos garantir queNOTE
sejaNOT NULL
para todosrow
emShipment
- Qualquer operação utilizando
NOTE
agora exigirá um esforço extra, devido à necessidade de fazer umJOIN
para garantir que estamos trabalhando com o registro correto
Embora seja ótimo que você esteja pensando nisso - eu consideraria isso uma micro-otimização. O SQL Server já possui otimizações incorporadas para manipulação
NVARCHAR(MAX)
e, geralmente, eu diria para não adivinhar até que se torne um problema. No entanto, há dois pontos principais que vieram à mente ao ler sua pergunta.A primeira é (como você mencionou no último ponto) haveria realmente algum desempenho obtido ao dividir os dados em outra tabela, deixando o SQL Server otimizar as páginas e os dados em si? Não tenho provas concretas comigo agora, mas suspeito que não. A razão é que, como você mencionou, seus dados estão regularmente acima de 8.000 bytes e, portanto, serão movidos para páginas LOB em sua tabela de notas de qualquer maneira. Você estaria apenas movendo o problema percebido de uma mesa para outra. Adicione a sobrecarga de executar um
JOIN
quando tiver que buscar os dados e você provavelmente acabará um pouco pior do que estava no início.Em segundo lugar, como você marcou a pergunta com design de banco de dados, minha recomendação real é que você divida as notas em outra tabela. No entanto, meu raciocínio não é tanto impulsionado pela otimização de desempenho, mas mais especificamente adicionando flexibilidade ao aplicativo. É muito provável que uma remessa precise de mais de uma nota anexada a ela (por exemplo, se estiver atrasada em trânsito, ou um cliente ligar etc...). Se você tiver a nota na própria remessa, fica mais difícil fazer isso sem duplicar os dados. Se você extraí-lo em sua própria tabela, poderá atribuir várias notas a uma remessa e rastrear quem as inseriu e quando. Isso torna seu aplicativo e banco de dados mais flexíveis.
Se você deseja otimizar, recomendo remover a necessidade de consultar as notas, a menos que alguém queira visualizá-las especificamente (como ter um formulário dedicado em seu aplicativo para fazer isso). Dessa forma, você só precisa realizar a junção/pesquisa quando alguém explicitamente deseja visualizar os dados. Mesmo que você não tenha externalizado as notas para outra tabela, não incluir a coluna na consulta se não for necessária removerá a necessidade de o SQL Server ler a página LOB. Se possível, sempre otimizaria as consultas para retornar a menor quantidade de informações necessárias antes de otimizar em um nível micro.
A resposta simples é não, a menos que você tenha um aplicativo que sempre busque todas as colunas da tabela e precise evitar que ele recupere as notas toda vez que consultar uma Remessa.
Se você decidir, pode instruir o SQL Server a nunca armazenar as notas na linha e usar um ponteiro para um LOB separado com a opção de tabela 'tipos de valor grande fora da linha' e pode até enviar esses LOBs para um grupo de arquivos separado por definindo a opção TEXTIMAGE_ON em CREATE TABLE .