Blogar é mais do que apenas tráfego – SQLBlog

Blogar é mais do que apenas tráfego - SQLBlog


Blogar é mais do que apenas tráfego - SQLBlog 1 Alguns anos atrás, Brent Ozar escreveu um post chamado “Blog para seu currículo, não para seus leitores”, e ele está totalmente certo. Eu queria compartilhar meus pensamentos sobre por que o blog é um cenário em que todos saem ganhando de várias maneiras, às vezes para o autor, outras para o leitor e, geralmente, ambas.

  • Documente suas realizações no trabalho. Pode ser fácil perder o controle dos problemas que você resolveu, mas não se você os estiver anotando. A publicação deles no mundo (ou mesmo apenas em um blog interno) obriga você a ter seu melhor controle de qualidade, demonstrar sua própria responsabilidade e melhorar sua capacidade de descrever o problema e a solução. Refazer suas etapas e documentar tudo também pode ajudar a antecipar perguntas que os leitores possam ter ou identificar soluções alternativas que você não considerou. Isso pode ser útil para você, seus colegas, seu chefe atual e seu próximo chefe.
  • Seja uma inspiração para os outros – incluindo o seu futuro eu. Ainda me orgulho de algumas das soluções que encontrei há 10 anos e ainda lembro de postagens antigas para refrescar minha mente sobre um problema semelhante que estou enfrentando hoje. Cenários em que eu estava apenas colocando algo totalmente documentado em minhas próprias palavras, e no contexto do meu próprio problema, podem ser suficientes para dar a alguém o momento da lâmpada que de outra forma não teria acontecido. Qualquer pessoa pode regurgitar o Books Online, mas destacar algo que a documentação não diz a você, ou mesmo apenas explicá-lo com suas próprias palavras, pode fazer toda a diferença no mundo. Se outras pessoas puderem aprender com suas postagens, podem ser mais incentivadas a escrever sobre suas próprias soluções.
  • Construa uma referência canônica. Foi por isso que comecei o aspfaq.com em 1999 – respondi muitas e muitas vezes às mesmas perguntas e lutei contra os mesmos mitos e contra-argumentos, uma FAQ opinativa parecia a solução ideal. Durante anos, serviu como minha própria referência para dezenas de trechos de código que eu escrevi, mas que desde então esqueci. Esse mesmo valor existe nas postagens que escrevi na semana passada, no mês passado e no ano passado. Eu escrevi o post Uma dica rápida ao usar vários contêineres do Docker e o SQL Server, não porque acho que há um grande número de pessoas por aí que precisam dessas informações, mas não preciso memorizar toda essa linha de comando. Eu queria estar inventando isso.

Não estou tentando parecer uma autoridade aqui. Cada um de nós pode ter nossos próprios motivos para publicar no blog e pode incluir itens como dinheiro, SEO e pontos de MVP. E todos podemos perceber um pouco diferente os benefícios de fazê-lo. Eu só queria compartilhar alguns dos resultados positivos que vejo e, talvez, fazer outra pessoa percebê-los também.

INSERT IN T-SQL Statement no SQL Server

EX9


Neste artigo, examinaremos profundamente a instrução INSERT INTO mostrando os diferentes formatos de sintaxe e cenários de uso para essa instrução.

A linguagem T-SQL é uma rica linguagem de programação de banco de dados que fornece um grande número de instruções e funções dinâmicas que nos ajudam a executar qualquer funcionalidade de maneiras diferentes, com base em nossas habilidades de desenvolvimento.

Uso

A instrução INSERT INTO T-SQL é usada principalmente para adicionar uma ou mais linhas à tabela de destino ou exibição no SQL Server. Isso pode ser feito fornecendo valores constantes na instrução INSERT INTO ou fornecendo a tabela ou exibição de origem da qual copiaremos as linhas.

Sintaxe

A instrução INSERT INTO T-SQL possui uma sintaxe dinâmica que se ajusta a todos os tipos de processos de inserção de dados. Para uma visão detalhada da instrução INSERT INTO T-SQL, consulte a documentação do Microsoft INSERT INTO.

A sintaxe da instrução INSERT INTO T-SQL usada para inserir uma única linha em uma tabela ou exibição do banco de dados do SQL Server é como:

Tabela INSERT INTO (coluna1, coluna2,…)

VALORES (expressão1, expressão2, …);

E a sintaxe da instrução INSERT INTO usada para inserir várias linhas de uma tabela de banco de dados de origem é como:

Tabela INSERT INTO (coluna1, coluna2,…)

SELECT expressão1, expressão2,…

FROM source_tables

[WHERE conditions];

Das instruções de sintaxe anteriores:

  • o tabela é o nome da tabela de destino na qual as linhas serão inseridas

  • Coluna1, coluna2 são os nomes das colunas na tabela de destino que serão preenchidas com os valores fornecidos
  • o expression1, expression2 são os valores que serão atribuídos às colunas mencionadas na tabela de destino com base na ordem fornecida. Leve em consideração que você deve fornecer os valores para todas as colunas NOT NULL na tabela de destino e, opcionalmente, fornecer valores para as colunas NULL

  • o source_tables é o nome da tabela da qual os valores serão copiados e inseridos na tabela de destino. Esses valores serão filtrados com base nas condições WHERE fornecidas

  • o PARA DENTRO A palavra-chave da instrução INSERT INTO é opcional

Começando

Para fins de demonstração, criaremos uma nova tabela de teste, que contém uma coluna IDENTITY, NULL e NOT NULL, e executaremos as alterações gradualmente nessa tabela para cobrir a maioria dos casos de uso comuns do INSERT INTO T- Instrução SQL.

A tabela de demonstração pode ser criada usando a instrução CREATE TABLE T-SQL abaixo:

Exemplos

A maneira simples de usar a instrução INSERT INTO para adicionar um novo registro à tabela criada é fornecer os valores em formato constante, onde os valores serão fornecidos para todas as colunas NULL e NOT NULL, exceto para as colunas geradas automaticamente, no ordem correta para as colunas na tabela de destino, como na instrução T-SQL abaixo:

Ao verificar a linha inserida na tabela de destino, você verá que o registro foi inserido com sucesso e atribuiu um valor de ID gerado automaticamente a 1, conforme mostrado abaixo:

EX1

Para inserir vários registros na mesma instrução INSERT INTO, em vez de escrever várias instruções de inserção, podemos fornecer os valores para cada linha no formato separado por vírgula, como na instrução T-SQL abaixo que insere três novas linhas na tabela de demonstração :

Ao verificar a tabela para as linhas recém-inseridas, você verá que três novos registros são inseridos na tabela de destino e atribuem valores de ID incrementados automaticamente, conforme mostrado abaixo:

EX2

Para inserir valores apenas para colunas específicas, devemos mencionar o nome dessas colunas e fornecer os valores para essas colunas na mesma ordem que na lista de colunas, levando em consideração que todas as colunas NOT NULL estão listadas e atribuídas, como na instrução T-SQL abaixo:

Na tabela de destino, você verá que uma nova linha é inserida com os valores das colunas atribuídos e o valor NULL para as colunas NULL que não são mencionadas na lista de colunas da instrução INSERT INTO T-SQL, conforme mostrado abaixo:

EX3

Você também pode fornecer a lista de colunas na instrução INSERT INTO em uma ordem diferente da ordem das colunas na tabela de destino, certificando-se de atribuir valores para as colunas na mesma ordem listada na instrução INSERT INTO, como na instrução T-SQL abaixo:

E o registro será inserido com sucesso, com o valor correto atribuído a cada coluna, conforme mostrado abaixo:

EX4

Se você tentar atribuir valores às colunas de nome e data de nascimento apenas na instrução INSERT INTO T-SQL, como na instrução abaixo:

A execução da instrução falhará, pois você deve atribuir valor à coluna NOT NULL do número de telefone na instrução INSERT INTO T-SQL, lembrando que todas as colunas NOT NULL são obrigatórias, conforme mostrado na mensagem de erro abaixo:

Erro1

Vamos modificar a tabela de destino adicionando uma nova coluna computada usada para calcular a idade de cada aluno, conforme mostrado abaixo:

Lembre-se de que o valor da coluna calculada será calculado automaticamente com base na equação definida, sem poder inserir esse valor explicitamente.

Ao verificar os dados da tabela de destino novamente, você verá que a idade é calculada automaticamente para todos os alunos, conforme mostrado abaixo:

EX5

Se você tentar inserir um valor explícito para a coluna computada, usando a instrução INSERT INTO abaixo:

A execução da instrução falhará, mostrando que você não pode modificar o valor calculado automaticamente da coluna calculada, conforme mostrado abaixo:

Erro2

Além disso, se você tentar inserir um valor explícito para a coluna ID, com a propriedade IDENTITY, que será automaticamente incrementada e gerada, como na instrução INSERT INTO abaixo:

A execução da instrução INSERT falhará, mostrando que você não pode inserir um valor explícito para a coluna de identidade gerada automaticamente, como na mensagem de erro abaixo:

Erro3

Para permitir a inserção de um valor explícito para a coluna de identidade, precisamos ativar a propriedade IDENTITY_INSERT antes de executar a instrução INSERT INTO e desabilitá-la após inserir o valor, certificando-se de mencionar o nome de todas as colunas NOT NULL e a coluna de identidade e atribua valores para a todas essas colunas na ordem correta, como na instrução T-SQL abaixo:

E a nova linha será inserida com sucesso com o valor de identidade fornecido explicitamente. Fornecer um valor explícito para a coluna de identidade não é altamente recomendado, a menos que você planeje copiar um registro para outra tabela com o mesmo valor de identidade, pois isso fará uma lacuna nos valores de identidade e começará a contar após o valor de ID fornecido, conforme mostrado abaixo:

EX6

Vamos modificar a tabela de destino novamente, adicionando uma nova coluna NULL de identificador exclusivo, levando em consideração que devemos fornecer um valor padrão a ser atribuído às colunas existentes, caso planejemos adicionar a coluna GUID como NOT NULL. A nova coluna pode ser adicionada usando a instrução ALTER TABLE T-SQL abaixo:

A coluna uniqueidentifier pode ser atribuída a valores usando a função interna NEWID () que gera um valor exclusivo em cada chamada, que pode ser facilmente usado na instrução INSERT INTO, como abaixo:

Verificando a tabela de destino, você verá que um valor NULL é atribuído a essa coluna GUID para todas as colunas existentes anteriormente e um valor GUID exclusivo atribuído à coluna recém-inserida, usando a função NEWID (), como mostrado abaixo:

EX7

A instrução INSERT INTO pode ser usada para adicionar valores à tabela de destino de outra tabela de origem, na qual você precisa fornecer a lista de colunas na tabela de destino e as colunas relacionadas da tabela de origem que possuem os valores a serem atribuídos ao colunas da tabela de destino, como na instrução T-SQL abaixo:

A instrução INSERT INTO anterior é usada para copiar 10 registros de duas tabelas de origem com base na lógica fornecida, e os registros inseridos serão os seguintes:

EX8

Podemos modificar a instrução INSERT INTO anterior controlando o número de colunas inseridas usando a opção TOP na cláusula INSERT, em vez de controlá-la na instrução SELECT da tabela de origem, conforme mostrado abaixo:

E os 10 registros serão copiados da tabela de origem e inseridos na tabela inserida, conforme mostrado no resultado abaixo:

EX9

A instrução INSERT INTO também pode ser usada para adicionar linhas a uma tabela de banco de dados localizada em um servidor remoto usando a instrução OPENQUERY quando houver um servidor vinculado para se conectar ao SQL Server remoto ou usando a instrução OPENDATASOURCE usando uma cadeia de conexão específica, como em T -SQL abaixo:

E o novo registro será inserido nessa tabela de banco de dados remoto, como mostrado abaixo:

EX10

É bom mencionar que a cláusula OUTPUT pode ser usada com a instrução INSERT INTO para recuperar informações de cada linha adicionada pela instrução INSERT executada. Essas informações podem ser usadas posteriormente como uma mensagem de confirmação do aplicativo ou para fins de arquivamento de dados.

No exemplo abaixo, criamos uma tabela temporária para armazenar os nomes dos alunos inseridos, como nesta instrução T-SQL:

Consultando a tabela temporária, o nome do aluno inserido será exibido, como abaixo:

EX11

Ahmad Yaseen
Últimas mensagens de Ahmad Yaseen (ver todos)

Introdução aos relacionamentos muitos para muitos no SSAS

Cube Data Model


Neste artigo, explicarei quais são os relacionamentos muitos para muitos no SSAS e como implementá-los em um projeto do SQL Server Analysis Services (SSAS). Para fins deste artigo, consideraremos apenas o Cubo Multidimensional e não o Tabular. Além disso, este artigo pressupõe que você tenha algum conhecimento justo sobre a criação de cubos SSAS do zero.

Freqüentemente, na modelagem de dimensões e fatos, os desenvolvedores de BI enfrentam o problema de lidar com relacionamentos muitos-para-muitos no modelo de dados. Em um banco de dados SQL ou data warehouse, é mais fácil implementar o mesmo; no entanto, fica complicado quando o mesmo modelo também precisa ser implementado em um cubo multidimensional.

Noções básicas sobre relacionamentos muitos para muitos

Vamos primeiro entender o que são muitos para muitos. Considere um exemplo simples de Alunos e Classe. Como você sabe, um aluno pode se inscrever em uma ou mais classes e uma classe pode ter um ou mais de um aluno. Este é um exemplo simples de relacionamento muitos para muitos. Outros casos semelhantes podem ser considerados entre Produtos e clientes. Um cliente pode comprar um ou mais produtos, enquanto um produto pode ser comprado por um ou vários clientes.

No entanto, não podemos definir esses tipos de relacionamentos muitos para muitos diretamente no SQL. Para implementar essas relações muitos-para-muitos em um modelo de dados relacionais, precisamos introduzir um mesa intermediária que tenha relações um-para-muitos com ambas as entidades. Vamos entender seguindo a figura abaixo:

Exemplo de relacionamento muitos para muitos

Figura 1 – Exemplo de relação muitos para muitos

Se você vê na figura acima, a tabela intermediária da ponte, neste caso, é a “Inscrição“, Que tem uma relação muitos-para-um com ambos Alunos e a Classe mesas. Da mesma forma, essa abordagem pode ser considerada para o design de qualquer outro modelo de dados em que os relacionamentos muitos-para-muitos precisem ser implementados.

Implementando relacionamentos muitos para muitos no SSAS

Agora que temos alguma idéia, vamos implementar relacionamentos muitos para muitos no SSAS. Para fins de demonstração, vou usar o banco de dados AdventureWorksDW2017, conforme fornecido pela Microsoft. Esse banco de dados está disponível para download gratuito e você pode instalar o mesmo na sua máquina local. Nesse data warehouse, também existem relações muitos para muitos, que indicam o motivo da compra ou venda de um item. Por exemplo, uma venda pode ter um ou mais motivos vinculados a ela e um motivo de vendas também pode ser vinculado a várias vendas. No armazém, a tabela Fato é a “FactInternetSales”(marcado em amarelo) e as dimensões são “DimSalesReason“E”DimProduct”(marcado em azul) Embora existam muitas outras dimensões e fatos no armazém, ele está fora do escopo deste artigo e não será abordado aqui. A tabela de ponte é criada usando o “FactInternetSalesReason”(destacado em vermelho)

Modelo AdventureWorksDW para muitos para muitos relacionamentos em ssas

Figura 2 – Modelo do AdventureWorksDW

Vamos agora avançar e construir relacionamentos muitos para muitos no SSAS. Você pode seguir as etapas mencionadas abaixo e criar o projeto.

Criando o projeto SSAS

Crie um novo Projeto multidimensional no SSAS.

Conecte-o ao AdventureWorksDW2017 banco de dados e crie o Visualização da fonte de dados adequadamente.

No Assistente de exibição da fonte de dados que aparecer, selecione as quatro tabelas, conforme ilustrado na figura abaixo.

Assistente de exibição da fonte de dados

Figura 3 – Assistente de exibição da fonte de dados

Clique em Próximo e complete o assistente.

Concluindo o Assistente de Exibição da Fonte de Dados

Figura 4 – Concluindo o Assistente de exibição da fonte de dados

Quando a Visualização da fonte de dados estiver pronta, o próximo passo é criar o Dimensões.

Criando as dimensões

Clique com o botão direito do mouse no Dimensão e selecione Nova dimensão.

Adicionando nova dimensão para muitos e muitos relacionamentos em ssas

Figura 5 – Adicionando nova dimensão

Selecione Use uma tabela existente e clique em Próximo.

Usando uma tabela existente

Figura 6 – Usando uma tabela existente

Selecione DimProduct como mesa e Chave do produto Enquanto o Coluna da chave e clique em Próximo.

Especificar dimensão de origem

Figura 7 – Especifique a dimensão da fonte

Selecione Nome do produto em inglês como o atributo e clique em Próximo e termine o assistente.

Selecionando atributos de dimensão para DimProduct

Figura 8 – Selecionando atributos de dimensão para DimProduct

Conclua as etapas semelhantes para DimSalesReason e complete o assistente.

Selecionando atributos de dimensão para DimSalesReason

Figura 9 – Selecionando atributos de dimensão para DimSalesReason

Criando o cubo

Agora que as dimensões estão prontas, o próximo passo é criar o cubo.

Clique com o botão direito do mouse em Cubo e selecione New Cube:

Adicionar um novo cubo

Figura 10 – Adicionar novo cubo

Selecione FactInternetSales e FactInternetSalesReason como grupos de medidas e clique em Próximo.

Selecione Grupos de medidas

Figura 11 – Selecionar grupos de medidas

Selecione Quantidade de vendas e Contagem de motivos de vendas na Internet como medida e clique Próximo.

Selecionar medidas

Figura 12 – Selecionar medidas

Quando todas as etapas acima estiverem concluídas, clique em Terminar para concluir e fechar o assistente.

Conclua o assistente de cubo

Figura 13 – Conclua o assistente de cubo

O cubo agora está criado e você pode ver o modelo de dados da seguinte maneira.

Modelo de Dados do Cubo

Figura 14 – Modelo de dados do cubo

Depois que o cubo for criado, implante o cubo no servidor. Clique com o botão direito do mouse no cubo e selecione Implantar.

Implantar o cubo

Figura 15 – Implantar o cubo

E finalmente, clique Processo para processar o cubo:

Processar o cubo

Figura 16 – Processar o cubo

Agora que nosso cubo foi processado, navegue pelo cubo e veja quais são os resultados. Arraste e solte o botão “Nome do Motivo de Vendas“,”Quantidade de vendas“E”Contagem de motivos de vendas na Internet”No designer de consulta. Como você pode ver na imagem abaixo, os valores para o Valor das vendas são os mesmos por todos os motivos incorretos. O motivo desse erro é que as relações muitos-para-muitos entre as tabelas de fatos ainda não estão definidas.

Navegando no Cubo

Figura 17 – Navegando no cubo

Definindo relacionamentos muitos para muitos no SSAS

Vamos agora definir relacionamentos muitos para muitos no SSAS. Você pode seguir as etapas abaixo.

Adicione uma nova dimensão para SalesOrderNumber. Como essa é a coluna que vamos usar na coluna da ponte, precisamos criar uma dimensão separada para a mesma.

Adicionando a nova dimensão

Figura 18 – Adicionando a nova dimensão

Deixe a coluna chave ser a mais SalesOrderNumber. Conclua o assistente clicando em Próximo e finalmente Terminar.

Concluindo o assistente

Figura 19 – Concluindo o assistente

Depois que a dimensão é criada, a próxima etapa é adicionar essa nova dimensão ao cubo.

Clique com o botão direito do mouse no Dimensões e selecione Adicionar dimensão do cubo.

Adicionar uma dimensão de cubo

Figura 20 – Adicionar dimensão do cubo

Navegue até o Uso da dimensão guia, e você verá a nova dimensão agora disponível na lista. Selecione SalesOrderNumber adjacente ao FactInternetSales e clique na pequena caixa à direita. Na janela que se abre, selecione o Tipo de Relacionamento Como Facto.

Definindo o tipo de relação de fatos

Figura 21 – Definindo o tipo de relação de fato

Selecione o grupo de medidas FactInternetSalesReason para SalesReason. Clique na pequena caixa à direita e, na caixa de diálogo exibida, selecione o Tipo de relação Como Muitos para muitos.

Definindo muitos para muitos relacionamentos em ssas

Figura 22 – Definindo relacionamentos muitos para muitos

Navegando no Cubo

Agora que implementamos as alterações necessárias necessárias para estabelecer relacionamentos muitos-para-muitos no SSAS, agora podemos prosseguir e começar a navegar no cubo, como fizemos na etapa anterior.

Navegando no Cubo

Figura 23 – Navegando no cubo

Se você vir a figura acima, agora poderá ver que os valores do Valor das vendas estão sendo exibidos corretamente agora. Além disso, se você o comparar com o exemplo anterior, poderá ver que alguns dos campos que não tinham relações apropriadas também são eliminados do cubo.

Conclusão

Neste artigo, expliquei como podemos implementar relacionamentos muitos para muitos no SSAS. O design de modelos de dados que incluam relações muitos-para-muitos é bastante complexo e precisa ser definido adequadamente. Se as relações não forem definidas corretamente, isso poderá levar a dados incorretos e, finalmente, informações enganosas.

A primeira vez que tive que restaurar um banco de dados


Mophead

Não é exatamente o mesmo período de tempo, mas não tão longe assim.

Lembro-me muito claramente.

Em meados dos anos 90, muito antes de ingressar na carreira de TI, eu trabalhava em um estúdio fotográfico em Muskegon, Michigan. Eles se especializaram em fotos da turma do ensino médio e fizeram muitos deles. Todas as manhãs, os fotógrafos vinham ao escritório para coletar impressões para as fotos que iriam tirar naquele dia – nome do aluno, endereço, hora das fotos, esse tipo de coisa.

Meus deveres no trabalho incluíam:

  • Removendo a fita de backup da noite anterior e trocando-a por uma nova
  • Executando algumas consultas ao banco de dados para preparar as sessões do dia
  • Impressão de compromissos e etiquetas para os fotógrafos

Uma manhã, executei uma consulta sem a cláusula WHERE. Porque é isso que você faz.

Não me lembro como as consultas funcionavam e nem me lembro como era o banco de dados. Só lembro que ele foi executado no SCO Xenix porque lembro dos manuais com muita clareza e lembro que não entrei em pânico. Eu sabia que ninguém mais havia acessado o banco de dados ainda – eu era um dos primeiros de todas as manhãs -, então tudo que eu precisava fazer era restaurar o banco de dados e seguir as etapas novamente.

Mas eu também lembro que o chefe (não gerente – patrão) tinha um épico temperamento. Tipo, xingar-e-jogar-coisas-e-fogo-tipo de temperamento. E, como eu, ele acordou cedo, e eu sabia que era apenas uma questão de tempo até ele aparecer e procurar suas impressões para ver quem ele iria fotografar naquele dia. Eu tinha certeza de que me entregaria a retaguarda e me resignei a esse fato.

Então, coloquei a fita da noite passada, iniciei a restauração e esperei. Com certeza, o chefe entrou e, antes que ele pudesse dizer qualquer coisa, eu disse:

Eu estraguei tudo, minha culpa e me desculpe. Eu estraguei as consultas que eu deveria executar, então estou restaurando o backup da noite passada e depois vou executar as consultas novamente e fazer as impressões. Você pode me demitir, se quiser, e eu entendo totalmente, se você quiser, mas provavelmente deve esperar para me demitir até que as restaurações terminem e eu faça as impressões. Ninguém mais aqui sabe como fazer isso, e os fotógrafos precisam trabalhar hoje.

Funcionou como um encanto. Ele assentiu, e eu percebi que ele estava chateado, mas ele não gritou ou jogou coisas. Ele apenas saiu bruscamente da sala de computadores e fez outras coisas.

Os fotógrafos e outras pessoas começaram a aparecer, procurando suas impressões. Expliquei que ainda não estavam prontos e expliquei o porquê. Todos eles tinham olhos grandes e perguntaram se o chefe sabia disso, e todos tinham certeza de que eu seria demitido.

Não fui demitido e todos ficaram surpresos. O chefe me usou como exemplo, dizendo: “Não, é isso que você deve fazer – confie quando fizer algo estúpido, conserte você mesmo e esteja pronto para lidar com as consequências”.

Parte de mim ficou um pouco decepcionada por não ter sido demitida. Eu não era um grande fã desse trabalho. Só fui demitido uma vez – de um Hardee -, mas isso é uma história para outra postagem no blog.

E se você? Você se lembra da primeira vez em que teve que fazer uma restauração no banco de dados para corrigir algo que atrapalhou?

Solucionar problemas de fuso horário, GMT e UTC usando o banco de dados T-SQL Toolbox

Testing the CONVERT_GETDATE_VALUE_FROM_ONE_TIMEZONE_TO_UTC user-defined function.


Introdução

Em breve, os aplicativos e o software de banco de dados que criamos lidarão com valores de data e hora. O banco de dados T-SQL Toolbox – um download gratuito – pode ajudar a resolver cálculos complexos com esses valores.

Eu moro nos EUA, assim como muitos de meus clientes. Devemos lidar com o horário de verão, o que significa que, em datas específicas, o horário local em um fuso horário específico pode avançar uma hora e, em outras datas, o horário local pode voltar uma hora. Essas mudanças acontecem em um agendamento definido. Uma mudança para frente sempre segue uma mudança para trás e uma mudança para trás sempre segue uma mudança para frente. Eles nunca se acumulam. Lidar com tudo isso na camada de banco de dados pode se tornar realmente complexo, e o T-SQL Toolbox pode economizar muito esforço com isso. Em uma conferência, ouvi um palestrante explicar que deveríamos usar o horário médio de Greenwich, ou GMT, para valores de data e hora do banco de dados para evitar esse problema. A GMT nunca muda para o horário de verão e podemos calcular facilmente os valores da hora local com base nos dados da GMT. Embora o SQL Server ofereça várias funções internas de data e hora, essas funções não tratam diretamente as conversões entre os valores do fuso horário local e o GMT, e certamente não tratam as conversões de horário de verão. Felizmente, encontrei o T-SQL Toolbox como uma maneira de evitar a criação das funções necessárias para tudo isso. Disponível aqui no CodePlex Archive e aqui no GitLab, o T-SQL Toolbox fornece UDFs (funções definidas pelo usuário) do SQL Server que convertem valores de data / hora entre fusos horários, incluindo GMT. O T-SQL Toolbox também fornece UDFs que calculam o início ou o fim

  • dia

  • semana

  • mês

  • trimestre

  • ano

Valores DateTime para um determinado valor de data / hora.

Baixar e instalar

Após o download:

Arquivo tsqltoolbox.zip baixado em um diretório host. Este arquivo possui um script para criar o banco de dados T-SQL Toolbox.

e extração de arquivos, como mostrado abaixo:

Subdiretórios TSqlToolbox.zip extraídos.

Como visto na captura de tela a seguir, faça uma busca detalhada no diretório sourceCode:

Faça uma busca detalhada no diretório sourceCode, para encontrar o arquivo sourceCode.zip.

Em seguida, faça uma busca detalhada no arquivo sourceCode.zip. Copie o arquivo TSqlToolbox.sql

Copie o arquivo TSqlToolbox.sql do arquivo ZIP do host.

Coloque o arquivo TSqlToolbox.sql em um diretório. Este script SQL criará o banco de dados T-SQL Toolbox.

Executaremos o arquivo TSqlToolbox.sql para instalar o banco de dados T-SQL Toolbox no SQL Server. Instalei-o em um ambiente do SQL Server 2014 Standard Edition em um PC com Windows 10.

O arquivo TSqlToolbox.sql possui um script CREATE DATABASE e conjuntos de scripts CREATE TABLE e CREATE FUNCTION. Abra o TSqlToolbox.sql em uma janela de consulta do SQL Server

As primeiras linhas do arquivo TSqlToolbox.sql. Este script criará o banco de dados T-SQL Toolbox.

Isso criará o banco de dados completo do TSqlToolbox, suas tabelas, linhas de dados da tabela, funções e restrições de chave primária / externa. Na captura de tela acima, o servidor de banco de dados FRANK-PC hospeda o TSqlToolbox. Todo banco de dados hospedado pelo servidor de banco de dados FRANK-PC pode usar as funções TSqlToolbox.

O Pesquisador de Objetos mostra as tabelas e funções do banco de dados T-SQL Toolbox.

Sob o capô

O banco de dados T-SQL Toolbox usa dados nas tabelas a seguir para seus cálculos.

  1. DateTimeUtil.Timezone

  2. DateTimeUtil.TimezoneAdjustmentRule

o Fuso horário A tabela possui uma linha para cada fuso horário definido no banco de dados.

A rede TimeZoneInfo A classe pode servir como fonte de dados principal para esta tabela porque, como visto aqui na documentação da Microsoft, esta classe tem as seguintes propriedades:

  • Eu iria

  • StandardName

  • Nome em Exibição

  • DaylightName

  • SupportsDaylightSavingTime

  • BaseUtcOffset

A caixa de ferramentas T-SQL TimezoneAdjustmentRule A tabela possui linhas que mostram alterações históricas de metadados para cada alteração de fuso horário, os atuais metadados definidos para cada fuso horário e planejadas alterações futuras para fusos horários específicos.

A rede TimeZoneInfo.AdjustmentRule A classe pode servir como fonte de dados primária para esta tabela porque, como visto aqui na documentação da Microsoft, suas propriedades e métodos refletem muitas das colunas desta tabela. Podemos ver isso claramente quando pesquisamos as propriedades DateEnd e DaylightTransitionStart dessa classe, por exemplo.

Usando o T-SQL Toolbox

Usaremos um banco de dados personalizado para trabalhar com o TSqlToolbox. Execute este script em uma janela de consulta do SQL Server:

Se necessário, ele primeiro cria um subdiretório, TSQL_TOOLBOX_DEMO na raiz e, em seguida, cria um novo banco de dados chamado TSQL_TOOLBOX_DEMO. Ele coloca os arquivos LDF e MDF do componente do banco de dados T-SQL Toolbox no diretório TSQL_TOOLBOX_DEMO. Por fim, cria o CONVERT_GETDATE_VALUE_FROM_ONE_TIMEZONE_TO_UTC procedimento armazenado, como mostrado.

Na instrução SELECT do procedimento armazenado, a terceira expressão nas linhas 25 e 26 chama o TSqlToolbox DateTimeUtil.UDF_ConvertLocalToUtcByTimezoneId função. Como muitas outras funções do TSqlToolbox, essa função é responsável pelo horário de verão por meio de chamadas para o TSqlToolbox.DateTimeUtil.TimezoneAdjustmentRule mesa.

A chamada nas linhas 25 e 26 coloca o nome do banco de dados TSqlToolbox na frente do nome completo da função. Em seguida, adiciona os parâmetros @timezoneID e GETDATE (). Observe que as funções possuem nomes de duas partes. “DateTimeUtil” serve como o prefixo de todos os nomes de funções do TSqlToolbox e um ponto separa o segundo nome de função de identificação. Se um nome de função TSqlToolbox não incluísse o prefixo “DateTimeUtil”, precisaríamos substituir o nome do esquema padrão do banco de dados TSqlToolbox. Geralmente usamos o dbo para isso; “Dbo” significa “proprietário do banco de dados”. No entanto, ambientes de banco de dados diferentes podem lidar com essa nomeação de maneira diferente; portanto, verifique com um administrador de banco de dados detalhes detalhados.

Uma função definida pelo usuário que mostra como chamar as funções de banco de dados do T-SQL Toolbox.

Na linha 5, o procedimento armazenado de demonstração possui código de teste para o próprio procedimento armazenado. O código de teste retorna esta linha:

Testando a função definida pelo usuário CONVERT_GETDATE_VALUE_FROM_ONE_TIMEZONE_TO_UTC.

Na linha 17, ele mapeia o parâmetro @timezoneID para o nome do fuso horário. A instrução Line 23 SELECT cria o conjunto de resultados do procedimento armazenado concluído. Isso mostra que, com uma chamada para uma função TSqlToolbox, podemos mapear facilmente um valor local de data e hora para um valor GMT. Nesse caso, tentamos uma chamada para GETDATE (). O TSqlToolbox é responsável por quaisquer efeitos locais do horário de verão.

Quando olhamos para as funções do banco de dados T-SQL Toolbox, podemos ver que ambos aproveitam as funções nativas do SQL Server e outras funções do TSqlToolbox. Por exemplo, a função UDF_GetStartOfDay primeiro converte o parâmetro @ReferenceDate – originalmente um tipo de dados DATETIME2 – em um tipo de dados DATE. Isso retira os dados de tempo do valor @ReferenceDate. Em seguida, ele converte esse valor intermediário novamente em um tipo de dados DATETIME2. Essa conversão restaurou os dados de horário, mas zerou o horário para o início do dia (SOD).

o [DateTimeUtil].[UDF_GetStartOfDay] Função TSqlToolbox.

A próxima captura de tela mostra as conversões equivalentes.

Cálculos para a caixa de ferramentas T-SQL [DateTimeUtil].[UDF_GetStartOfDay] função.

Como visto abaixo, a função TSqlToolbox UDF_ConvertLocalToLocalByTimezoneIdentifier chama a TSqlToolbox: UDF_ConvertUtcToLocalByTimezoneIdentifier e UDF_ConvertLocalToUtcByTimezoneIdentifier funcionam para converter um fuso horário DATETIME2 em outro parâmetro do fuso horário. Os dois primeiros parâmetros têm valores da coluna [TSqlToolbox].[DateTimeUtil].[Timezone].Identificador.

o [DateTimeUtil].[UDF_ConvertLocalToLocalByTimezoneIdentifier] Função TSqlToolbox.

Estender TSqlToolbox

Como explicado anteriormente, o banco de dados T-SQL Toolbox oferece funções para calcular o início ou o fim do dia, semana, etc. Valores de DateTime para um determinado valor DATETIME2. Podemos facilmente estender essas funções. Por exemplo, criei e adicionei a função UDF_GetEndOfDecade, vista aqui, ao meu banco de dados TSqlToolbox local. Ele calcula o valor DATETIME2 do final da década para um determinado parâmetro DATETIME2.

Esta função calcula primeiro o valor de final de ano (EOY) para o parâmetro de entrada. Em seguida, ele analisa esse valor EOY em valores separados de mês, dia e ano. O cálculo da variável @YearOffset usa a função% (mod) para calcular o número de anos restantes na década do valor do parâmetro ano. Por fim, a instrução primeiro reúne um valor de data final de todos os valores do componente e, em seguida, usa a função UDF_GetEndOfDay para converter esse valor em um valor de retorno DATETIME2.

Atualizar dados internos da caixa de ferramentas T-SQL

As funções do banco de dados TSqlToolbox dependem dos dados em suas tabelas Timezone e TimezoneAdjustmentRule para seus cálculos. Obviamente, esses dados não são alterados nas próprias tabelas. Matt Johnson-Pint, da Microsoft, foca na engenharia de fuso horário do Windows. Em seu blog, ele discutiu como os fusos horários mudam constantemente. Nesse segmento de estouro de pilha, ele explicou que o Windows armazena informações de fuso horário no registro. Ele forneceu mais detalhes sobre como isso funciona neste encadeamento de estouro de pilha. Embora o banco de dados T-SQL Toolbox tenha um valor enorme, precisamos lembrar que seus dados principais podem se tornar obsoletos sem atualizações. O processo de atualização do Microsoft Windows atualiza as informações de fuso horário do registro; portanto, o registro de um dispositivo totalmente atualizado deve ter as informações mais recentes sobre o fuso horário. Criei esse aplicativo de desktop do Windows C-Sharp para consultar o registro e retornar os dados das classes .Net TimeZoneInfo e TimeZoneInfo.AdjustmentRule. Essas classes consultam os valores do fuso horário do registro, que podemos usar para atualizar o T-SQL Toolbox. O aplicativo usa um símbolo de tubo “|” delimitar os valores da coluna nas linhas. Também construí esta versão do VB.net, que funciona da mesma maneira. Hospedei as versões C-Sharp e VB.net na minha página do GitHub. Ambos incluem soluções completas do Visual Studio 2015 e arquivos executáveis ​​concluídos.

Aplicativos do Visual Studio .Net que consultam o registro do Windows para mostrar informações de fuso horário.

Para criar tabelas do SQL Server com os dados de saída do aplicativo, primeiro atualize o Windows na máquina de desenvolvimento. Isso aplicará todas as atualizações de fuso horário ao registro. Em seguida, execute o aplicativo e copie as linhas das caixas de texto do formulário. Use Ctrl-C para copiar porque o formulário usa caixas de rich text. Coloque as linhas em novos arquivos de texto. Trunque as tabelas do banco de dados TSqlToolbox que você atualizará para que eles tenham dados completamente atualizados. Use o Assistente para Importação e Exportação do SQL Server para importar os valores para as tabelas do banco de dados T-SQL Toolbox. Se esse assistente falhar devido a problemas com os dados, reformate os dados para uma instrução INSERT do SQL Server e continue com as instruções INSERT em uma janela de consulta. Para criar os relacionamentos de tabela pai / filho, adicione colunas de ID de valor inteiro às tabelas como chaves primárias e estrangeiras.

Conclusão

Como vimos, o T-SQL Toolbox resolve problemas complicados e retorna um valor enorme. Ainda melhor, podemos estendê-lo facilmente e atualizar seus dados para cobrir uma gama crescente de regras e requisitos de negócios.

Frank Solomon
Últimas mensagens de Frank Solomon (ver todos)

Reorganização de um escritório menor – parte 3 – SQLBlog

Reorganização de um escritório menor - parte 3 - SQLBlog


Descrevi as primeiras fases da revisão do meu escritório em casa na parte 1 e na parte 2. A última fase está ocorrendo bem a tempo, pois estamos agachados no auto-isolamento para ajudar a achatar a curva do Covid-19.

Uma casa normalmente silenciosa durante o horário escolar agora está agitada com minhas meninas, de 5 e 7 anos, constantemente procurando novas fontes de entretenimento, conflito e caos.

Isso significa PORTAS.

Nosso primeiro andar é um conceito relativamente aberto; não muitas portas ou paredes. A abertura para o meu escritório é arqueada com mais de 90 “de altura e 80” de largura, o que excluía correr para Lowe’s ou Home Depot e pegar algumas portas padrão para pendurar (clique para ampliar):

Reorganização de um escritório menor - parte 3 - SQLBlog 2

Isso significa PERSONALIZADAS portas

Olhando do meu escritório para a sala de jantar, você pode ver duas grandes janelas lá, de frente para o leste. Isso significa que, pela manhã, o sol está muito claro e essas persianas quase sempre estão fechadas (clique para ampliar):

Reorganização de um escritório menor - parte 3 - SQLBlog 3

Isso significa portas personalizadas que refratar a luz.

Conversamos com quatro fornecedores locais e acabamos voltando com o primeiro que visitamos, o Shed Brand Studio. Essas pessoas são conhecidas mais por seus trabalhos com vitrais, mas ficamos impressionados com o artesanato nas portas que vimos em seu showroom, bem como com a vontade de sentar e nos permitir atender aos requisitos. Pode ser diferente onde você está, mas o prazo de entrega de um projeto como esse não foi inferior a 6 semanas para nenhum desses fornecedores, e não tenho certeza de qual efeito o Covid-19 terá sobre isso.

Escolhemos a madeira de Sapele, tanto para combinar com o piso quanto, principalmente, para bloquear o som. Essa madeira é muito densa e cada porta pesa – se você pode acreditar – cerca de 225 libras. Escolhemos vidro ondulado de vidro duplo que refrataria luz suficiente para reduzir o brilho, mas não tanto que criaria uma masmorra. Conversamos sobre as laterais e / ou um painel de popa (painéis fixos ao lado / acima das portas), mas isso levaria a um projeto ainda mais complicado e, IMHO, uma aparência menos natural.

No momento, suspendemos o restante do projeto (acabamento de moldagem / acabamento e uma porta frontal correspondente) apenas para eliminar mais uma fonte de interação e para continuar o auto-isolamento. As portas estão abertas e estão servindo ao propósito a que se destinam por enquanto, cortando uma boa quantidade de som e luz da manhã suficiente para deixar as cortinas da sala de jantar abertas. Até agora, muito feliz, mesmo que as bordas ainda não pareçam bem, e a porta da frente adjacente ainda seja branca e com vidro ligeiramente diferente.

Reorganização de um escritório menor - parte 3 - SQLBlog 4Reorganização de um escritório menor - parte 3 - SQLBlog 5Reorganização de um escritório menor - parte 3 - SQLBlog 6

Agora só preciso pintar essas mesas mais claras com uma cor que não seja madeira (pensando em cinza claro) e adicionar uma luz “no ar” do lado de fora das portas (estou brincando aqui).

Ajude com melhorias em STRING_SPLIT

Ajude com melhorias em STRING_SPLIT


Ajude com melhorias em STRING_SPLIT 7 Estamos no meio do ciclo entre lançamentos, onde ainda não estamos ouvindo sobre nenhum dos recursos planejados para o SQL Server vNext. Este é provavelmente o melhor momento para pressionar a Microsoft por melhorias, desde que possamos apoiar nossos pedidos com casos de negócios legítimos. No SQL Server 2016, STRING_SPLIT resolveu uma lacuna que faltava há muito tempo em um idioma que, reconhecidamente, não era destinado ao processamento complicado de cadeias. E é isso que eu quero trazer hoje.

Por anos antes do SQL Server 2016 (e desde então), escrevemos nossas próprias versões, as aprimoramos ao longo do tempo e até discutimos sobre quem era mais rápido. Nós escrevemos sobre cada microssegundo que conseguimos ganhar e eu, por exemplo, afirmei várias vezes: “este é meu último post sobre como dividir strings!” No entanto, aqui estamos nós.

Eu sempre argumentarei que os parâmetros com valor de tabela são a maneira correta de separar as strings. Mas enquanto Eu Como esses blobs de vírgula separados por vírgula nunca devem ser expostos ao banco de dados dessa forma, a divisão de strings continua sendo um caso de uso predominante – algumas das postagens do meu blog estão entre as 5 principais visualizações todo dia.

Então, por que as pessoas ainda estão tentando dividir strings com funções com valor de tabela quando existe uma substituição superior? Alguns, tenho certeza, porque ainda estão em versões mais antigas, presos em um nível de compatibilidade mais antigo ou não conseguem se separar de forma alguma porque os TVPs não são suportados pelo idioma ou pelo ORM. Quanto ao resto, enquanto STRING_SPLIT é conveniente e eficiente, não é perfeito. Possui restrições que sofrem algum atrito e tornam a substituição de chamadas de função existentes por uma chamada nativa complicada ou impossível.

Aqui está a minha lista.

Essas limitações não são exaustivas, mas listei as importantes em meu ordem de prioridade (e Andy Mallon também publicou um blog sobre isso hoje):

  • Delimitador de um caractere
    Parece que a função foi criada com apenas o caso de uso simples: CSV. As pessoas têm seqüências mais complexas do que 1,2,3 ou A|B|Ce geralmente são alimentados em seus bancos de dados a partir de sistemas fora de seu controle. Como descrevo nesta resposta e nesta dica, existem maneiras de contornar isso (operações de substituição realmente ineficientes), mas são realmente feias e, francamente, desfazem todos os benefícios de desempenho oferecidos pela implementação nativa. Além disso, parte do atrito com esse se refere especificamente a: “Bem, o PostgreSQL string_to_array lida com vários delimitadores de caracteres; então, por que o SQL Server não pode? ”

    Implementação: aumente o tamanho máximo de separator.

  • Nenhuma indicação de ordem de entrada
    A saída da função é um conjunto e, inerentemente, os conjuntos não têm ordem. E enquanto na maioria dos casos você verá uma string de entrada como bob,ted,frank sair nessa ordem (bob ted frank), não há garantia (com ou sem desleixo) (ORDER BY (SELECT NULL)) hackear). Muitas funções domésticas incluem uma coluna de saída para indicar a posição ordinal na sequência, o que pode ser importante se a lista estiver organizada em uma ordem definida ou se a posição ordinal exata tiver algum significado.

    Implementação: adicione um opção para incluir a coluna de posição ordinal na saída.

  • O tipo de saída é baseado apenas na entrada
    A coluna de saída da função é fixada em varchar ou nvarchar, e é determinado com precisão pelo comprimento de toda a cadeia de entrada, não pelo comprimento do elemento mais longo. Então, você tem uma lista de 25 letras, o tipo de saída é finalmente varchar(51). Para cadeias mais longas, isso pode resultar em problemas com concessões de memória, dependendo do uso, e pode apresentar problemas se o consumidor confiar em outro tipo de dados que está sendo produzido (por exemplo, int, que às vezes especifica funções para evitar conversões implícitas posteriormente). Como solução alternativa, os usuários às vezes criam suas próprias tabelas temporárias ou variáveis ​​de tabela e despejam a saída da função antes de interagir com ela, o que pode levar a problemas de desempenho.

    Implementação: adicione uma opção para especificar o tipo de saída de value.

  • Não é possível ignorar elementos vazios ou delimitadores à direita
    Quando você tem uma string como a,,,b,, você pode esperar que apenas dois elementos sejam gerados, pois os outros três estão vazios. A maioria dos TVFs personalizados que eu vi cortam delimitadores à direita e / ou filtram cadeias de comprimento zero, mas STRING_SPLIT retorna todas as 5 linhas. Isso dificulta a troca na função nativa porque você também precisa adicionar uma lógica de agrupamento para eliminar essas entidades.

    Implementação: adicione uma opção para ignorar elementos vazios.

  • Não é possível filtrar duplicatas
    Essa é provavelmente uma solicitação menos comum e fácil de resolver usando DISTINCT ou GROUP BY, mas muitas funções fazem isso automaticamente para você. Não há diferença real no desempenho nesses casos, mas existe algo que você se esquece de adicionar (pense em uma lista grande, com muitas duplicatas, juntando-se a uma tabela grande).

    Implementação: adicione uma opção para filtrar duplicatas.

Aqui está o caso de negócios.

Tudo isso parece teórico, mas aqui está o caso comercial, que posso garantir que é muito real. Na Wayfair, temos uma propriedade substancial do SQL Server e temos literalmente dezenas de equipes diferentes que criaram suas próprias funções com valor de tabela ao longo dos anos. Alguns são melhores que outros, mas todos são chamados de milhares e milhares de linhas de código. Recentemente, iniciamos um projeto em que estamos tentando substituí-los por chamadas para STRING_SPLIT, mas nos deparamos com casos de bloqueio envolvendo várias das limitações acima.

Alguns são fáceis de contornar, usando uma função de wrapper. Mas o delimitador de caractere único limitação nos forçou a avaliar a solução alternativa terrível usando REPLACE, e isso provou eliminar o benefício de desempenho que esperávamos, fazendo-nos acelerar. E, nesses casos, perdemos um chip de negociação importante ao pressionar por atualizações para o nível de compatibilidade (nem todos os bancos de dados estão em 130, não importa 140). Nesses casos, estamos perdendo não apenas STRING_SPLIT melhorias, mas também em outras 130 + melhorias de desempenho que estaríamos desfrutando se STRING_SPLIT foi convincente o suficiente por si só para promover a atualização do nível compat.

Então, estou pedindo sua ajuda.

Visite este item de feedback:

Vote! Mais importante, Deixe um comentário descrevendo casos de uso reais que você faz STRING_SPLIT uma dor ou um não iniciante para você. Apenas os votos não são suficientes, mas, com feedback tangível e qualitativo, há uma chance de que eles comecem a levar a sério essas lacunas.

Sinto vontade de apoiar delimitadores com vários caracteres (até, digamos, expandindo de [n]varchar(1) para [n]varchar(5)) é uma melhoria não intrusiva que desbloqueia muitas pessoas que compartilham meu cenário. Outros aprimoramentos podem ser mais difíceis de implementar, alguns exigindo sobrecargas e / ou aprimoramentos de idioma; portanto, não espero todas essas correções no vNext. Mas mesmo uma pequena melhoria reiteraria que STRING_SPLIT foi um investimento que valeu a pena e que não será abandonado (como, por exemplo, bancos de dados contidos, um dos recursos mais famosos de drive-by).

Obrigado pela atenção!

Erros ilógicos podem ser um fator do plano – SQLBlog

Erros ilógicos podem ser um fator do plano - SQLBlog


Erros ilógicos podem ser um fator do plano - SQLBlog 8 Eu já falei sobre erros ilógicos antes. Em várias respostas sobre administradores de banco de dados (um, dois, três), mostro como você pode usar um CASE expressão ou TRY_CONVERT para solucionar um erro em que um valor não numérico, que deveria ter sido filtrado por uma cláusula de junção ou outra, ainda leva a um erro de conversão. Erland Sommarskog criou um item de Conexão mais de uma década atrás, ainda não endereçado, chamado “SQL Server não deve gerar erros ilógicos”.

Recentemente, tivemos um cenário em que uma consulta estava falhando em um servidor, mas não em outro. Mas isso foi um pouco diferente; não havia números envolvidos. Imagine este cenário: uma tabela de origem possui uma coluna que é varchar(20). Uma consulta cria uma variável de tabela com uma coluna que é varchar(10)e insere linhas da tabela de origem, com um filtro no lugar que expõe apenas valores com 10 caracteres ou menos.

Em muitos casos, é claro, esse cenário é perfeitamente adequado e tudo funciona como esperado.

CREATE TABLE dbo.src(i int, a varchar(20));
 
INSERT dbo.src VALUES(1,'aaaaa'),(2,'bbbbbbbbbbbbbbb');
 
DECLARE @t table(a varchar(10));
 
INSERT @t SELECT a FROM dbo.src WHERE i = 1;
 
DROP TABLE dbo.src;

Se você mudar isso para WHERE i = 2;, porém, você receberá esta * mensagem de erro:

Msg 2628, Nível 16, Estado 1
Os dados de sequência ou binários seriam truncados na tabela ‘tempdb.dbo. # A60B3C91’, coluna ‘a’. Valor truncado: ‘bbbbbbbbbb’.

Não há surpresas aqui; é assim que deve funcionar.

Um exemplo mais complexo

Quando o esquema e as consultas ficam mais complicadas, o plano se torna importante. Aqui está um cenário um pouco mais complicado, mas mantido o mais simples possível, para demonstrar o problema:

CREATE TABLE dbo.t1(id int NOT NULL, s varchar(5) NOT NULL);
CREATE TABLE dbo.t2(id int NOT NULL);
 
INSERT dbo.t1 (id, s) VALUES (1, 'l=3'), (2, 'len=5'), (3, 'l=3');
INSERT dbo.t2 (id)    VALUES (1), (3), (4), (5);
GO
 
DECLARE @t table(dest varchar(3) NOT NULL);
 
INSERT @t(dest) SELECT t1.s 
  FROM dbo.t1 
  INNER JOIN dbo.t2 ON t1.id = t2.id;
GO
 
DROP TABLE dbo.t1, dbo.t2;

Isso gera um erro semelhante ao que vimos anteriormente:

Msg 2628, Nível 16, Estado 1
Dados binários ou de string seriam truncados na tabela ‘tempdb.dbo. # AC65D70E’, coluna ‘dest’. Valor truncado: ‘len’.

Embora devamos ter recuperado apenas linhas com valores que cabem na coluna de destino (id é 1 ou 3, pois essas são as únicas duas linhas que correspondem aos critérios de junção), a mensagem de erro indica que a linha em que id também foi retornado 2, mesmo sabendo que não poderia ter sido. Vamos olhar para o estimado plano (com desculpas por essa terminologia a Grant, Hugo e Erin):

Plano derivado de Plano derivado de “Explain” no Azure Data Studio

Você pode ver o CONVERT_IMPLICIT lá, o que você acha que deveria ter tornado esse erro impossível. Você também pode ver que a correspondência de hash tem apenas duas linhas saindo, mas algo que falta nos diagramas é quantas linhas vão para dentro um operador e, nesse caso, a folha de propriedades do operador revela que a tabela de origem é usada para materializar o lado da construção. É aqui que o erro ocorre, porque a conversão implícita precisa ser avaliada.

Posso mostrar algumas maneiras pelas quais, sem alterar a consulta, podemos fazer o erro desaparecer (ou reaparecer).

Dados diferentes

Com apenas uma alteração nos dados de origem:

CREATE TABLE dbo.t1(id int NOT NULL, s varchar(5) NOT NULL);
CREATE TABLE dbo.t2(id int NOT NULL);
 
INSERT dbo.t1 (id, s) VALUES (1, 'l=3'), (2, 'len=5'), (3, 'l=3');
INSERT dbo.t2 (id)    VALUES (1), (3), (4);--, (5);
GO
 
DECLARE @t table(dest varchar(3) NOT NULL);
 
INSERT @t(dest) SELECT t1.s 
  FROM dbo.t1 
  INNER JOIN dbo.t2 ON t1.id = t2.id;
GO
 
DROP TABLE dbo.t1, dbo.t2;

Desta vez, a correspondência de hash não gera erroDesta vez, a correspondência de hash não gera erro

Ainda temos uma correspondência de hash, mas observe que o lado da construção e o lado do probe foram trocados, um efeito colateral de dados ligeiramente diferentes. Como a tabela de hash não precisa mais materializar o resultado da conversão implícita, nenhum erro ocorre.

Esquema diferente

Outra “solução” é adicionar um índice em cluster ao dbo.t2 (e volte a inserir as 4 linhas originais):

CREATE TABLE dbo.t1(id int NOT NULL, s varchar(5) NOT NULL);
CREATE TABLE dbo.t2(id int PRIMARY KEY CLUSTERED);
 
INSERT dbo.t1 (id, s) VALUES (1, 'l=3'), (2, 'len=5'), (3, 'l=3');
INSERT dbo.t2 (id)    VALUES (1), (3), (4), (5);
GO
 
DECLARE @t table(dest varchar(3) NOT NULL);
 
INSERT @t(dest) SELECT t1.s 
  FROM dbo.t1 
  INNER JOIN dbo.t2 ON t1.id = t2.id;
GO
 
DROP TABLE dbo.t1, dbo.t2;

Aqui está como o plano muda:

Agora obtemos uma junção de loops aninhados e nenhum erroAgora obtemos uma junção de loops aninhados e nenhum erro

o CONVERT_IMPLICIT ainda está lá no escalar de computação, mas a avaliação não é forçada antes que a linha ruim seja eliminada, porque a junção de loops aninhados não precisa materializar nada.

Consulta diferente

Você também pode alterar a consulta; por exemplo, você pode aplicar funções como LEFT, SUBSTRINGou um explícito CONVERT (ou CAST) para a coluna:

CREATE TABLE dbo.t1(id int NOT NULL, s varchar(5) NOT NULL);
CREATE TABLE dbo.t2(id int NOT NULL);
 
INSERT dbo.t1 (id, s) VALUES (1, 'l=3'), (2, 'len=5'), (3, 'l=3');
INSERT dbo.t2 (id)    VALUES (1), (3), (4), (5);
GO
 
DECLARE @t table(dest varchar(3) NOT NULL);
 
INSERT @t(dest) SELECT s = LEFT(t1.s, 3) -- or SUBSTRING(t1.s, 1, 3)
                                         -- or CONVERT(varchar(3), t1.s)
  FROM dbo.t1                            -- or CAST(t1.s AS varchar(3))
  INNER JOIN dbo.t2 ON t1.id = t2.id;
GO
 
DROP TABLE dbo.t1, dbo.t2;

A transformação subjacente aqui é implementada como um SUBSTRING, e isso fornece ao otimizador informações suficientes para saber que nenhum valor pode ter mais de três caracteres:

Nenhum erro ao aplicar LEFT ()Nenhum erro ao aplicar LEFT ()

Você também pode aplicar um WHERE cláusula para eliminar as linhas explicitamente. Isso funciona nesse caso específico, mas, como demonstrado nas postagens acima, isso nem sempre funciona (nem usa uma CTE ou tabela derivada):

CREATE TABLE dbo.t1(id int NOT NULL, s varchar(5) NOT NULL);
CREATE TABLE dbo.t2(id int NOT NULL);
 
INSERT dbo.t1 (id, s) VALUES (1, 'l=3'), (2, 'len=5'), (3, 'l=3');
INSERT dbo.t2 (id)    VALUES (1), (3), (4), (5);
GO
 
DECLARE @t table(dest varchar(3) NOT NULL);
 
INSERT @t(dest) SELECT t1.s
  FROM dbo.t1 
  INNER JOIN dbo.t2 ON t1.id = t2.id
  WHERE LEN(t1.s) <= 3;
GO
 
DROP TABLE dbo.t1, dbo.t2;

O plano é agora:

Nenhum erro com um filtro explícitoNenhum erro com um filtro explícito

Nesse caso, a linha incorreta é filtrada com antecedência suficiente para que se torne irrelevante a maneira como a correspondência de hash opera.

Você também pode tentar sugerir uma junção de loop para evitar a correspondência de hash e, provavelmente, meia dúzia de outras maneiras de alterar a consulta para forçar a filtragem anterior ou eliminar a materialização.

Observe que algumas dicas podem trazer o erro de volta. Por exemplo, neste caso, OPTION (FORCE ORDER) (ou qualquer dica que preserve a ordem) traz t1 de volta ao lado da compilação da combinação de hash e o erro retorna:

CREATE TABLE dbo.t1(id int NOT NULL, s varchar(5) NOT NULL);
CREATE TABLE dbo.t2(id int NOT NULL);
 
INSERT dbo.t1 (id, s) VALUES (1, 'l=3'), (2, 'len=5'), (3, 'l=3');
INSERT dbo.t2 (id)    VALUES (1), (3), (4), (5);
GO
 
DECLARE @t table(dest varchar(3) NOT NULL);
 
INSERT @t(dest) SELECT t1.s
  FROM dbo.t1 
  INNER JOIN dbo.t2 ON t1.id = t2.id
  OPTION (FORCE ORDER);
GO
 
DROP TABLE dbo.t1, dbo.t2;

Um grama de prevenção …

Uma solução mais lógica é alterar a variável da tabela para combinar tipos de dados ou, se dados mais longos não fizerem sentido na tabela de origem, conserte na fonte. Isso pode ter efeitos de gotejamento, mas, geralmente, o problema decorre da origem, permitindo valores muito grandes. Corrija a fonte e é improvável que declarações muito grandes em outros lugares causem problemas, a menos que sejam preenchidas por outras fontes.

Enquanto isso, verifique se não há dados errados que estejam causando explicitamente o erro, fazendo você seguir o seu caminho. Não seria a primeira vez que o código seria responsabilizado quando dados defeituosos (ou melhor, um esquema permissivo demais) estavam realmente com defeito.

Conclusão

Meu objetivo aqui não é explicar como solucionar o erro, é mais que você pode ou não ver o erro de truncamento, mesmo quando não faz sentido. E você pode ver o inverso acontecer – um código que funcione com facilidade pode ser interrompido repentinamente quando alguém adiciona dados, atualiza estatísticas, cria ou reconstrói um índice ou ocorre um failover ou a reinicialização do serviço.

O esquema e os dados subjacentes podem desempenhar um papel no plano que você obtém e outros fatores podem fazer com que você obtenha planos diferentes em servidores diferentes ou mesmo no mesmo servidor em momentos diferentes, mesmo quando o esquema e os dados são os mesmos .

Enorme grito para Paul White, cuja contribuição inestimável tornou esta postagem muito melhor do que poderia ter sido.



Onde descobrir os principais relógios de quartzo Rolex – SQLServerCentral


Quem, a fim de trabalhar realmente? Muitos não. De fato, eu iria tão longe quanto a experiência em condições que a maioria dos humanos é um tanto preguiçosa e não consegue trabalhar por muito. Sempre dizemos: “É possível que haja uma maneira livre de problemas para executar isso”. As pessoas compram para gastar e dinheiro. O dinheiro estende o mundo todo e quando o seu produto economiza dinheiro para as pessoas, efetivamente interessado. E, se o seu produto ganhar dinheiro para as pessoas, efetivamente jogue.

Onde descobrir os principais relógios de quartzo Rolex - SQLServerCentral 9Se você possui um relógio Rolex, seja ele próprio ou o proprietário, r11 e eu aprecio que você duvide do seu valor ao negociá-lo, hoje é definitivamente um momento preciso para avaliar. Na última década, o valor do rollex11 foi recentemente aumentado com sucesso. Por um lado, as pessoas começaram a alterar sua opinião sobre um. Agora, o login do rollex11 é considerado obra de arte, elemento que aprecia a ocasião. Como são fabricados com materiais eficientes no setor interno, o tipo de artesanato que o verdadeiro mestre pode executar, eles foram além de coletivamente. intenção, que é simplesmente informar o tempo.

Perfect Timing pode oferecer a você um preço de mercado premium premium para seu relógio Rolex para aqueles que desejam comprar um novo Rolex e vender o antigo. A etiqueta de custo oferecida por nossa empresa é adicional à venda em um site de licitações, sem nenhum risco ou despesa em descontos ou outros locais de venda. Nosso processo de compra de relógios Rolex antigos é básico. Entre em contato conosco primeiro para obter um preço aproximado do antigo relógio Rolex que você decide vender.

Considere um relógio adequado para uso específico para o seu trabalho. A construção do trabalho de uma pessoa ou outros locais de trabalho intensivos em mão-de-obra e um grande relógio durável podem suportar os danos que você parece estar enfrentando.

Claro, pode ser usado de maneira negativa e alguns por aí fazem. Mas eles sempre acabam em um problema importante. O uso dessas informações para obter ganhos positivos, já que para vender seus produtos, você está em boas condições e é simplesmente um bom vendedor.

As pessoas compram para ganhar conforto. Arrecadar mais de US $ 3.000 apenas para um novo sofá é um desejo fácil de obter mais benefícios. Conseguir esse novo couro no carro esportivo é obter mais conforto (entre outros gatilhos). Viver a Internet O estilo de vida também é uma maneira de obter mais tranquilidade. Quero dizer, afinal, quem deseja combater a hora do rush todos os dias ou prestar contas a algum chefe, ou apertar o botão de soneca às 5 da manhã de segunda a sábado?

A roda Robur Bufflex é uma roda de polimento popular com um novo acabamento acetinado. É ideal para ser usado em todos os metais. A roda Bufflex de cetim fino acaba sendo usada por joalheiros e relojoeiros em todo o mundo. Cria um acabamento acetinado suave que é idêntico ao acabamento de fábrica em caixas e pulseiras de relógio. Pode fabricado na França, portanto, tem 100 mm por 25 mm dimensão. A peça central é costurada com couro de forma segura, mas possui três seções de um polimento de superfícies múltiplas completamente eficaz.

Para algumas empresas, ficar na página considerada uma das SERPS (Páginas de resultados dos mecanismos de pesquisa) será um pouco mais valioso do que ter o anúncio da página real nas Páginas Amarelas. Aquelas listas telefônicas grossas estão associadas ao dinossauro, eu garanto. A partir de agora, qual será o custo eficiente para publicar, imprimir e distribuir esses livros quando ninguém os usa ou deseja mais acumulá-los?

Design de banco de dados e verificação lógica para otimização de consultas SQL

Normalization with SQL Server Query Optimization using Integer references


O design do banco de dados e a verificação lógica desempenham um papel vital no desempenho do banco de dados e na otimização da consulta SQL. Ambos têm parâmetros diferentes para tornar seu banco de dados e a consulta precisos.

Otimização de consulta SQL

Design do Banco de Dados

O design do banco de dados desempenha um papel essencial no lado do desempenho do banco de dados. Se a estrutura da tabela não estiver em termos adequados de distribuição de dados e de maneira normalizada, isso poderá gerar o desafio significativo de alterar a estrutura conforme e quando um problema aparecer na imagem. Discutiremos alguns parâmetros abaixo para ter em mente quando projetarmos o banco de dados.

Normalização

A normalização é uma técnica para estruturar dados relacionais na forma de esquema e tabela para reduzir a redundância de dados e evitar a anomalia de dados. A relação de dados pode ser projetada em 1NF, 2NF, 3NF, conforme necessário, com a natureza das informações. No lado do desempenho, a Normalização reduz as operações de E / S, evitando a inserção / atualização / exclusão de anomalia.
    A normalização da estrutura do banco de dados causa menos quantidade de armazenamento em comparação com dados não estruturados no SQL
    Banco de dados do servidor. Você pode entender mais aqui: o que é normalização de banco de dados no SQL Server?

Por exemplo:

Temos uma tabela com Merchant_stock com detalhes de Item, Comerciante, Quantidade disponível, Preço. O normalizamos para finalizar o nível com as referências da tabela de pesquisa no último formulário normalizado.

Normalização com otimização de consulta do SQL Server usando referências de número inteiro

Quando um usuário deseja obter detalhes do status do comerciante, da cidade e do comerciante com o item em estoque, ele pode
    junte várias tabelas com a cláusula de Chave Primária das tabelas de pesquisa.

A normalização do nível final reduz a redundância da tabela. Por exemplo: um usuário deseja alterar a cidade ou o status do comerciante, (n) o número de linhas será afetado na instrução de atualização com o primeiro caso da tabela de exemplo acima (merchant_stock). E no segundo caso, apenas uma linha será afetada no
Comerciante mesa. Novamente, a alteração do nome do status atualizará (n) linhas no segundo caso. Portanto, no terceiro caso, a referência Inteira é usada para o staus do comerciante para evitar as linhas de atualização (n) na tabela.

Os tipos estáticos de campos devem ser armazenados sempre na tabela de pesquisa, e usar a referência inteira na tabela de detalhes é a melhor prática para o design do banco de dados com a normalização.

Índices

Os índices são uma referência a uma pesquisa rápida nas informações. Um índice é uma ferramenta poderosa para localizar diretamente os dados de destino, em vez de varrer a tabela inteira e encontrar as linhas necessárias na tabela. O uso de um índice em cluster ou não em cluster é fazer padrões de correspondência rápida de dados. O índice melhora o desempenho geral da consulta com o uso inteligente dele. O SQL Server nos permite criar um índice com o número de opções abaixo, e cada uma delas tem um papel significativo no desempenho da consulta.

Opções de índice:

  • ALLOW_PAGE_LOCKS

  • ALLOW_ROW_LOCKS

  • COMPRESSÃO DE DADOS

  • DROP_EXISTING

  • FATOR DE PREENCHIMENTO

  • IGNORE_DUP_KEY

  • MAX_DURATION

  • MAXDOP (max_degree_of_parallelism)

  • CONECTADOS

  • OPTIMIZE_FOR_SEQUENTIAL_KEY

  • PAD_INDEX

  • RESUMABLE

  • SORT_IN_TEMPDB

  • STATISTICS_INCREMENTAL

  • STATISTICS_NORECOMPUTE

Partição de tabela

A Partição de Tabela do SQL Server é uma maneira de distribuir os dados pelo sistema de arquivos com o conjunto de configurações definidas pelo usuário.
    regras. Quando estamos trabalhando em uma tabela de tamanho grande, a opção de filtro de linha também está disponível; no entanto, é comparativamente mais lento em comparação com a opção Partição de tabela. Quando usamos a Partição da tabela na tabela, o
    O filtro de consulta terá como alvo a parte necessária da tabela e retornará o conjunto de resultados com relativa rapidez. Um filtro de consulta decidirá se concentrar em uma parte ou partição específica da tabela pelo esquema de partição. O uso adequado da partição da tabela e o design da tabela oferecem excelente desempenho de consulta na tabela grande.

Os usuários podem adicionar o grupo de arquivos e os arquivos ao banco de dados para usar a partição com a tabela. Por exemplo:

Balanceamento de linhas

Manter linhas em uma única tabela para todos os clientes não é a única solução em uma solução de banco de dados baseada em produto. Para as diferentes bases geográficas de clientes, os dados precisam ser armazenados no banco de dados de acordo com a geografia do cliente para atender aos problemas de latência e melhor otimização da Consulta SQL. Um aplicativo pode ser implantado em vários locais para executar atividades diferentes; no entanto, o local de inserção do banco de dados será único. Portanto, podemos ter um
    banco de dados configurado com as mesmas tabelas em vários sites e, de acordo com o cliente, as solicitações de geografia podem ser atendidas no banco de dados de destino.

Restrições

O SQL Server Query Optimizer sempre verifica a chave estrangeira e as restrições para preparar um plano de execução de consultas eficiente, e cada execução é executada no plano de execução. O otimizador do SQL Server é muito confiável e inteligente; se houver alguma restrição na coluna, o plano de execução ignorará a parte desnecessária das verificações de manipulação de dados.

Confirmação lógica

A verificação lógica faz parte do processo de consulta e dos parâmetros de desempenho relacionados. Estratégias de consulta diferentes
    com a maneira mais eficiente, são as soluções certas para o SQL Query Optimization. Aqui vamos discutir alguns
    parâmetros abaixo para ter em mente quando escrevemos uma consulta, Procedimento, Função ou Acionador.

Estrutura JOIN

JUNTE-SE estrutura com a ordem incorreta da tabela afeta o desempenho da consulta quando várias tabelas são
    presente em junções com várias condições na cláusula “Onde”. O otimizador de consulta sempre se refere à ordem da tabela nas junções e a altera de acordo para preparar o plano de execução. No entanto, o otimizador não seguirá todos os pedidos possíveis com a instrução de consulta. Portanto, os desenvolvedores precisam tentar ordenar a tabela na consulta preparada com um mapeamento individual. A ordem incorreta das tabelas na consulta de junção consome mais recursos no servidor e afeta outras consultas também no SQL Server.

Otimização de consultas SQL com pedidos JOIN adequados

Expressão de relação

A expressão relacional na cláusula WHERE é significativa para a otimização da consulta SQL. SE EXISTE, SE NÃO EXISTE, NÃO
    IN, IN, CASE WHEN e muitas outras condições podem ser usadas na cláusula WHERE. O uso sem visão das condições faz com que
    tempo de execução surpreendente e plano de execução também. Mesmo NOT IN pode ser substituído por LEFT JOIN por IS NULL
    condição também, que não é conhecida por muitos desenvolvedores. Que tipo de expressão pode ser usada e quando isso depende da natureza e dos tipos de dados? Para tornar sua consulta rápida e otimizada, depende da lógica que está sendo
    escrito pelo desenvolvedor.

Por exemplo:

Ou

3. Classificação de Dados

A classificação de dados é uma parte cara da execução da consulta no SQL Server. Os usuários podem evitar o uso de classificação desnecessária no programa SQL Server porque ele armazena o resultado da consulta definido no buffer para classificá-lo em uma referência de ordem específica. Mesmo uma opção de índice do SQL Server fornece uma opção para armazenar dados com a classificação, mais uma vez, é o trabalho do otimizador de consultas fazer um plano perfeito de execução de consultas.

Por exemplo: um índice é definido com a opção da coluna de classificação e os retornos das linhas da tabela também estarão em ordem; no entanto, a instrução SQL pode ter vários campos na cláusula ORDER BY. Portanto, isso pode fazer com que vários problemas processem os dados para classificar na ordem das colunas no termo ORDER BY. O usuário precisa usar os campos obrigatórios apenas para ter a classificação de dados em um conjunto de resultados específico apenas para evitar a classificação desnecessária de dados no procedimento.

Opções SET

Quando estamos trabalhando em um banco de dados de tamanho grande ou com uma boa experiência em SQL Query Optimization, definitivamente nós
    podem enfrentar problemas como: plano de execução múltipla para o procedimento único no SQL Server, consulta ou procedimento
    acelerar a execução no SSMS, mas não no aplicativo, os erros podem ser retornados pelo aplicativo para o
    procedimento (procedimento aninhado), mas funciona bem usando o SSMS, e muitos outros problemas podem ser resolvidos com a ajuda da declaração SET Options no SQL Server.

Quando executamos uma consulta usando o SSMS, ele usa as Opções SET configuradas padrão do SSMS. Se o aplicativo usa SET
    Opções, definidas no procedimento ou definidas na Conexão SQL, portanto, pode haver diferentes
    maneiras de execução para o mesmo procedimento pelo otimizador de consultas do SQL Server e para fazer vários planos de execução com
    um conjunto de opções SET.

Por exemplo:

DEFINIR ARITHABORT EM A instrução é necessária com a instrução ou procedimento de consulta 0 quando a operação aritmética está sendo usada
    na consulta.

NÍVEL DE ISOLAMENTO

SQL Server ISOLATION LEVEL significa controle de simultaneidade da transação e
    ÁCIDO (Atomicidade, Consistência, Isolamento e Durabilidade). NÍVEL DE ISOLAMENTO para cada transação determina a integração de dados com o bloqueio no nível da linha para usuários com nível diferente e por quanto tempo a transação deve reter bloqueios para proteger os dados contra essas alterações. O usuário pode definir o NÍVEL DE ISOLAMENTO nas conexões do banco de dados,
    e solicitações com o comando de SET TRANSACTION ISOLATION LEVEL LEIA NÃO COMPROMISSO / LEIA COMPROMISSO / REPETÍVEL LEIA / SERIALIZABLE. Até o usuário pode alterar o ISOLATION LEVEL no mesmo comando entre a execução para diferentes finalidades, para visibilidade de dados e otimização de consultas SQL.

Por exemplo:

Os usuários podem usar WITH (NOLOCK) com o nome da tabela na consulta para buscar dados não confirmados lidos. Para o procedimento, o
    A instrução SET pode ser escrita com ISOLATION LEVEL para ser aplicada a todas as tabelas do procedimento.

Chamada remota

A chamada remota a é uma consulta ou procedimento cruzado do SQL Server para solicitar ou executar operação no site remoto. Os usuários podem executar qualquer uma das operações INSERT / UPDATE ou DELETE usando consultas remotas com a ajuda do Servidor Vinculado. Até o usuário pode ingressar na tabela remota na tabela de banco de dados do servidor local também. Uma consulta remota não é considerada uma coisa ruim no SQL Server; no entanto, se filtrarmos ou manipularmos os dados remotos no servidor local que afeta o desempenho da consulta, para obter melhor desempenho, o usuário poderá executar o procedimento remoto no servidor local.

O procedimento remoto é uma boa opção para a otimização da Consulta SQL, escreva sua lógica no procedimento no
    servidor remoto finalize e execute esse procedimento com o servidor vinculado no SQL Server local.

Conclusão

A otimização de consultas do SQL Server pode ser uma tarefa difícil, especialmente quando se lida com um banco de dados grande, em que mesmo as pequenas alterações podem ter um impacto negativo no desempenho existente da consulta e do banco de dados.

Os parâmetros discutidos acima são relevantes para o design do banco de dados e a gravação da consulta. O produto e o banco de dados serão confiáveis ​​e melhores, pois os parâmetros acima são definidos e usados ​​com precisão no seu banco de dados.

Jignesh Raiyani
Últimas mensagens de Jignesh Raiyani (ver todos)