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 / user-37801

PicoDeGallo's questions

Martin Hope
PicoDeGallo
Asked: 2019-03-06 15:54:59 +0800 CST

Índices não clusterizados para colunas definidas em uma chave primária composta

  • 3

Eu tenho um banco de dados multilocatário em que estou utilizando uma AccountIdcoluna em todas as tabelas como parte da chave primária composta para isolamento de locatário. É benéfico criar índices não clusterizados adicionais em cada coluna que faz parte da Chave Primária composta para ajudar o SQL Server a manter estatísticas precisas e melhorar o desempenho da consulta ao ingressar em tabelas de pesquisa?

Por exemplo, dentro de uma tabela associativa que define relacionamentos um-para-muitos entre um Accounte o americano Stateem que eles têm escritórios, em teoria qual das duas opções é preferível dada a seguinte estrutura e consulta de amostra?

Crie as tabelas Accounte Statee preencha com dados de amostra.

DROP TABLE IF EXISTS [dbo].[Account];
DROP TABLE IF EXISTS [dbo].[State];

-- [Account] table and sample values.
IF OBJECT_ID('[dbo].[Account]', 'U') IS NULL
BEGIN
    CREATE TABLE [dbo].[Account] (
        [AccountId] [int] IDENTITY(1,1) NOT NULL
        ,[AccountAlias] [varchar](3) NOT NULL
        ,[AccountName] [varchar](128) NOT NULL
        ,CONSTRAINT [PK_Account] PRIMARY KEY CLUSTERED ([AccountId] ASC)
        ,CONSTRAINT [UQ_Account_Alias] UNIQUE NONCLUSTERED ([AccountAlias] ASC)
        ,CONSTRAINT [UQ_Account_Name] UNIQUE NONCLUSTERED ([AccountName] ASC)
    );

    SET IDENTITY_INSERT [dbo].[Account] ON;

    INSERT INTO [dbo].[Account] ([AccountId], [AccountAlias], [AccountName])
    VALUES (1, 'SA1', 'Sample Account 1'), (2, 'SA2', 'Sample Account 2'), (3, 'SA3', 'Sample Account 3')

    SET IDENTITY_INSERT [dbo].[Account] OFF;
END;
GO

-- [State] table and sample values.
IF OBJECT_ID('[dbo].[State]', 'U') IS NULL
BEGIN
    CREATE TABLE [dbo].[State] (
        [StateId] [tinyint] IDENTITY(1,1) NOT NULL
        ,[StateCode] [varchar](2) NOT NULL
        ,[StateName] [varchar](32) NOT NULL
        ,CONSTRAINT [PK_State] PRIMARY KEY CLUSTERED ([StateId] ASC)
        ,CONSTRAINT [UQ_State_Code] UNIQUE NONCLUSTERED ([StateCode] ASC)
        ,CONSTRAINT [UQ_State_Name] UNIQUE NONCLUSTERED ([StateName] ASC)
    );

    SET IDENTITY_INSERT [dbo].[State] ON;

    INSERT INTO [dbo].[State] ([StateId], [StateCode], [StateName])
    VALUES (1, 'AL', 'Alabama'), (2, 'AK', 'Alaska'), (3, 'AZ', 'Arizona'), (4, 'AR', 'Arkansas'), (5, 'CA', 'California')

    SET IDENTITY_INSERT [dbo].[State] OFF;
END;
GO

Criar AccountStateOPÇÃO 1 - apenas chave primária composta

DROP TABLE IF EXISTS [dbo].[AccountState];

IF OBJECT_ID('[dbo].[AccountState]', 'U') IS NULL
BEGIN
    CREATE TABLE [dbo].[AccountState] (
        [AccountId] [int] NOT NULL
        ,[StateId] [tinyint] NOT NULL
        ,CONSTRAINT [PK_AccountState] PRIMARY KEY CLUSTERED ([AccountId] ASC, [StateId] ASC)
        ,CONSTRAINT [FK_AccountState_Account] FOREIGN KEY ([AccountId]) REFERENCES [dbo].[Account]([AccountId])
        ,CONSTRAINT [FK_AccountState_State] FOREIGN KEY ([StateId]) REFERENCES [dbo].[State]([StateId])
    );

    INSERT INTO [dbo].[AccountState] ([AccountId], [StateId])
    SELECT A.[AccountId], S.[StateId]
    FROM [dbo].[Account] A CROSS JOIN [dbo].[State] S
    WHERE A.[AccountId] = 1 AND S.[StateId] IN (1, 2, 3)
    UNION
    SELECT A.[AccountId], S.[StateId]
    FROM [dbo].[Account] A CROSS JOIN [dbo].[State] S
    WHERE A.[AccountId] = 2 AND S.[StateId] IN (3, 4, 5)
    UNION
    SELECT A.[AccountId], S.[StateId]
    FROM [dbo].[Account] A CROSS JOIN [dbo].[State] S
    WHERE A.[AccountId] = 3 AND S.[StateId] IN (1, 3, 5)
END;
GO

Criar AccountStateOPÇÃO 2 - chave primária composta + índices não clusterizados

DROP TABLE IF EXISTS [dbo].[AccountState];

IF OBJECT_ID('[dbo].[AccountState]', 'U') IS NULL
BEGIN
    CREATE TABLE [dbo].[AccountState] (
        [AccountId] [int] NOT NULL
        ,[StateId] [tinyint] NOT NULL
        ,CONSTRAINT [PK_AccountState] PRIMARY KEY CLUSTERED ([AccountId] ASC, [StateId] ASC)
        ,CONSTRAINT [FK_AccountState_Account] FOREIGN KEY ([AccountId]) REFERENCES [dbo].[Account]([AccountId])
        ,CONSTRAINT [FK_AccountState_State] FOREIGN KEY ([StateId]) REFERENCES [dbo].[State]([StateId])
        ,INDEX [IX_AccountState_Account] NONCLUSTERED ([AccountId])
        ,INDEX [IX_AccountState_State] NONCLUSTERED ([StateId])
    );

    INSERT INTO [dbo].[AccountState] ([AccountId], [StateId])
    SELECT A.[AccountId], S.[StateId]
    FROM [dbo].[Account] A CROSS JOIN [dbo].[State] S
    WHERE A.[AccountId] = 1 AND S.[StateId] IN (1, 2, 3)
    UNION
    SELECT A.[AccountId], S.[StateId]
    FROM [dbo].[Account] A CROSS JOIN [dbo].[State] S
    WHERE A.[AccountId] = 2 AND S.[StateId] IN (3, 4, 5)
    UNION
    SELECT A.[AccountId], S.[StateId]
    FROM [dbo].[Account] A CROSS JOIN [dbo].[State] S
    WHERE A.[AccountId] = 3 AND S.[StateId] IN (1, 3, 5)
END;
GO

Consulta de amostra

SELECT
    A.[AccountName]
    ,S.[StateName]
FROM
    [dbo].[AccountState] A_S
    JOIN [dbo].[Account] A
        ON A_S.[AccountId] = A.[AccountId]
    JOIN [dbo].[State] S
        ON A_S.[StateId] = S.[StateId]
WHERE
    S.[StateCode] = 'CA'

Das duas opções, que tipo de combinação de índice seria visto como mais adequado para escala? Somente chave primária composta ou chave primária composta mais índices não clusterizados adicionais? Ou existe outra opção mais viável?

sql-server database-design
  • 1 respostas
  • 751 Views
Martin Hope
PicoDeGallo
Asked: 2018-06-20 13:19:35 +0800 CST

Ordem de operação com LTRIM/RTRIM/ISNULL

  • 2

A ordem de operação que você coloca LTRIMe RTRIMimporta quando usada em conjunto com ISNULL? Por exemplo, veja o exemplo a seguir em que um usuário potencialmente insere vários espaços em um campo, mas cortamos sua entrada para ser um NULLvalor real para evitar o armazenamento de strings vazias.

Estou realizando as TRIMoperações fora de ISNULL:

DECLARE @Test1 varchar(16) = '    '

IF LTRIM(RTRIM(ISNULL(@Test1,''))) = ''
BEGIN
    SET @Test1 = NULL
END

SELECT @Test1

Isso retorna adequadamente um valor verdadeiro NULL. Agora vamos colocar ISNULLdo lado de fora:

DECLARE @Test2 varchar(16) = '    '

IF ISNULL(LTRIM(RTRIM(@Test2)),'') = ''
BEGIN
    SET @Test2 = NULL
END

SELECT @Test2

Isso também retorna um NULLvalor. Ambos funcionam bem para o uso pretendido, mas estou curioso para saber se há alguma diferença em como o otimizador de consulta SQL lida com isso?

sql-server t-sql
  • 2 respostas
  • 5677 Views
Martin Hope
PicoDeGallo
Asked: 2018-04-17 07:51:31 +0800 CST

O consumo de "Memória Total do Servidor" do SQL Server estagnou por meses com mais de 64 GB disponíveis

  • 40

Eu me deparei com um problema estranho em que o SQL Server 2016 Standard Edition de 64 bits parecia ter se limitado a exatamente metade da memória total alocada para ele (64 GB de 128 GB).

A saída de @@VERSIONé:

Microsoft SQL Server 2016 (SP1-CU7-GDR) (KB4057119) - 13.0.4466.4 (X64) 22 de dezembro de 2017 11:25:00 Copyright (c) Microsoft Corporation Standard Edition (64 bits) no Windows Server 2012 R2 Datacenter 6.3 ( Build 9600: ) (Hipervisor)

A saída de sys.dm_os_process_memoryé:

sys.dm_os_process_memory

Quando eu consulto sys.dm_os_performance_counters, vejo que Target Server Memory (KB)está em 131072000e Total Server Memory (KB)está em pouco menos da metade disso em 65308016. Na maioria dos cenários, eu entenderia que isso é um comportamento normal, pois o SQL Server ainda não determinou que precisa alocar mais memória para si mesmo.

No entanto, ele está "preso" em ~ 64 GB há mais de 2 meses. Durante esse período, realizamos uma quantidade significativa de operações com uso intensivo de memória em alguns dos bancos de dados e adicionamos cerca de 40 bancos de dados à instância. Temos um total de 292 bancos de dados, cada um com arquivos de dados pré-alocados em 4 GB com taxa de crescimento automático de 256 MB e arquivos de log de 2 GB com taxa de crescimento automático de 128 MB. Eu executo um backup completo uma vez à noite às 00h00 e começo os backups de log de transações de segunda a sexta-feira, das 6h00 às 20h00 em um intervalo de 15 minutos. Esses bancos de dados são relativamente baixos em sua taxa de transferência geral, mas estou cético de que algo esteja errado, já que o SQL Server não se aproximou doTarget Server Memorynaturalmente por meio de novas adições de banco de dados, execuções normais de consulta, bem como pipelines ETL com uso intensivo de memória que foram executados.

A própria instância do SQL Server está sobre um servidor Windows Server 2012R2 virtualizado (VMware) com 12 CPUs, 144 GB de memória (128 GB para SQL Server, 16 GB reservados para Windows) e 4 discos virtuais totais que ficam sobre um vSAN com unidades SAS de 15.000 . O Windows fica naturalmente em um disco C: de 64 GB com um arquivo de paginação de 32 GB. Os arquivos de dados ficam em um disco D: de 2 TB, os arquivos de log ficam em cima de um disco L: de 2 TB e o tempdb fica em um disco T: de 256 GB com arquivos de 8 x 16 GB sem crescimento automático.

Verifiquei que não há outras instâncias do SQL Server em execução no servidor além do MSSQLSERVER.

Serviços

Esse servidor é totalmente dedicado apenas à instância do SQL Server, portanto, não temos outros aplicativos ou serviços em execução que possam consumir memória.

Monitor de recursos

Eu utilizo o RedGate SQL Monitor para análise, e abaixo está um histórico dos últimos 18 dias de Total Server Memory. Como você pode ver, a utilização de memória permaneceu totalmente estagnada, exceto por um único aumento de ~ 300 MB no início de abril.

Monitor SQL RedGate

Qual pode ser a causa disso? O que posso examinar mais de perto para determinar por que o SQL Server não deseja usar os 64 GB + de memória adicionais alocados para ele?

A saída de execução sp_Blitz:

sp_Blitz @OutputType = 'markdown', @CheckServerInfo = 1;

Prioridade 50: Desempenho :

  • CPU Schedulers Offline - Alguns núcleos de CPU não são acessíveis ao SQL Server devido a problemas de licenciamento ou mascaramento de afinidade.

  • Nós de memória offline - devido a problemas de licenciamento ou mascaramento de afinidade, parte da memória pode não estar disponível.

Prioridade 50: Confiabilidade :

  • Remote DAC Disabled - O acesso remoto à Dedicated Admin Connection (DAC) não está habilitado. O DAC pode tornar a solução de problemas remota muito mais fácil quando o SQL Server não responde.

Prioridade 100: Desempenho :

  • Muitos planos para uma consulta - 300 planos estão presentes para uma única consulta no cache do plano - o que significa que provavelmente temos problemas de parametrização.

  • Acionadores do servidor ativados

    • O acionador do servidor [RG_SQLLighthouse_DDLTrigger] está habilitado. Certifique-se de entender o que esse gatilho está fazendo - quanto menos trabalho ele fizer, melhor.

    • O acionador do servidor [SSMSRemoteBlock] está ativado. Certifique-se de entender o que esse gatilho está fazendo - quanto menos trabalho ele fizer, melhor.

Prioridade 150: Desempenho :

  • Consultas forçando dicas de junção - 1.480 instâncias de dicas de junção foram registradas desde a reinicialização. Isso significa que as consultas estão dominando o otimizador do SQL Server e, se elas não souberem o que estão fazendo, isso pode causar mais danos do que benefícios. Isso também pode explicar por que os esforços de ajuste do DBA não estão funcionando.

  • Consultas forçando dicas de pedidos - 2.153 instâncias de dicas de pedidos foram registradas desde a reinicialização. Isso significa que as consultas estão dominando o otimizador do SQL Server e, se elas não souberem o que estão fazendo, isso pode causar mais danos do que benefícios. Isso também pode explicar por que os esforços de ajuste do DBA não estão funcionando.

Prioridade 170: Configuração do Arquivo :

  • Banco de dados do sistema na unidade C

    • master - O banco de dados master possui um arquivo na unidade C. Colocar bancos de dados do sistema na unidade C corre o risco de travar o servidor quando ficar sem espaço.

    • model - O banco de dados do modelo possui um arquivo na unidade C. Colocar bancos de dados do sistema na unidade C corre o risco de travar o servidor quando ficar sem espaço.

    • msdb - O banco de dados msdb tem um arquivo na unidade C. Colocar bancos de dados do sistema na unidade C corre o risco de travar o servidor quando ficar sem espaço.

Prioridade 200: Informativo :

  • Trabalhos do agente iniciando simultaneamente - vários trabalhos do SQL Server Agent são configurados para iniciar simultaneamente. Para listas de programação detalhadas, consulte a consulta na URL.

  • Tabelas no mestre do banco de dados mestre - A tabela CommandLog no banco de dados mestre foi criada por usuários finais em 30 de julho de 2017, 17h22. As tabelas no banco de dados mestre não podem ser restauradas em caso de desastre.

  • TraceFlag ativado

    • O sinalizador de rastreamento 1118 está habilitado globalmente.

    • O sinalizador de rastreamento 1222 está habilitado globalmente.

    • O sinalizador de rastreamento 2371 está habilitado globalmente.

Prioridade 200: Configuração de servidor não padrão :

  • Agent XPs - Esta opção sp_configure foi alterada. Seu valor padrão é 0 e foi definido como 1.

  • backup checksum default - Esta opção sp_configure foi alterada. Seu valor padrão é 0 e foi definido como 1.

  • padrão de compactação de backup - Esta opção sp_configure foi alterada. Seu valor padrão é 0 e foi definido como 1.

  • limite de custo para paralelismo - Esta opção sp_configure foi alterada. Seu valor padrão é 5 e foi definido como 48.

  • grau máximo de paralelismo - Esta opção sp_configure foi alterada. Seu valor padrão é 0 e foi definido como 12.

  • max server memory (MB) - Esta opção sp_configure foi alterada. Seu valor padrão é 2147483647 e foi definido como 128000.

  • otimizar para cargas de trabalho ad hoc - esta opção sp_configure foi alterada. Seu valor padrão é 0 e foi definido como 1.

  • mostrar opções avançadas - Esta opção sp_configure foi alterada. Seu valor padrão é 0 e foi definido como 1.

  • xp_cmdshell - Esta opção sp_configure foi alterada. Seu valor padrão é 0 e foi definido como 1.

Prioridade 200: Confiabilidade :

  • Procedimentos armazenados estendidos no mestre

  • master - O procedimento armazenado estendido [sqbdata] está no banco de dados master. O CLR pode estar em uso e o banco de dados mestre agora precisa fazer parte do planejamento de backup/recuperação.

    • master - O procedimento armazenado estendido [sqbdir] está no banco de dados master. O CLR pode estar em uso e o banco de dados mestre agora precisa fazer parte do planejamento de backup/recuperação.

    • master - O procedimento armazenado estendido [sqbmemory] está no banco de dados master. O CLR pode estar em uso e o banco de dados mestre agora precisa fazer parte do planejamento de backup/recuperação.

    • master - O procedimento armazenado estendido [sqbstatus] está no banco de dados master. O CLR pode estar em uso e o banco de dados mestre agora precisa fazer parte do planejamento de backup/recuperação.

    • master - O procedimento armazenado estendido [sqbtest] está no banco de dados master. O CLR pode estar em uso e o banco de dados mestre agora precisa fazer parte do planejamento de backup/recuperação.

    • master - O procedimento armazenado estendido [sqbtestcancel] está no banco de dados master. O CLR pode estar em uso e o banco de dados mestre agora precisa fazer parte do planejamento de backup/recuperação.

    • master - O procedimento armazenado estendido [sqbteststatus] está no banco de dados master. O CLR pode estar em uso e o banco de dados mestre agora precisa fazer parte do planejamento de backup/recuperação.

    • master - O procedimento armazenado estendido [sqbutility] está no banco de dados master. O CLR pode estar em uso e o banco de dados mestre agora precisa fazer parte do planejamento de backup/recuperação.

    • master - O procedimento armazenado estendido [sqlbackup] está no banco de dados master. O CLR pode estar em uso e o banco de dados mestre agora precisa fazer parte do planejamento de backup/recuperação.

Prioridade 210: Configuração de banco de dados não padrão :

  • Read Committed Snapshot Isolation Enabled - Esta configuração de banco de dados não é o padrão.

    • RedGate

    • RedGateMonitor

  • Isolamento de Instantâneo Habilitado - Esta configuração de banco de dados não é o padrão.

    • RedGate

    • RedGateMonitor

Prioridade 240: Estatísticas de espera :

  • 1 - SOS_SCHEDULER_YIELD - 1770,8 horas de espera, 115,9 minutos de tempo médio de espera por hora, 100,0% de espera de sinal, 1419212079 tarefas em espera, 4,5 ms de tempo médio de espera.

Prioridade 250: Informativo :

  • SQL Server está sendo executado em uma conta NT Service - estou executando como NT Service\MSSQLSERVER. Eu gostaria de ter uma conta de serviço do Active Directory.

Prioridade 250: Informações do Servidor :

  • Conteúdo de rastreamento padrão - O rastreamento padrão contém 36 horas de dados entre 14 de abril de 2018 23h21 e 16 de abril de 2018 11h13. Os arquivos de rastreamento padrão estão localizados em: C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Log

  • Espaço C da unidade - 196816,00 MB livres na unidade C

  • Espaço D da unidade - 894823,00 MB livres na unidade E

  • Espaço L da unidade - 1361367,00 MB livres na unidade F

  • Espaço na unidade T - 114441,00 MB livres na unidade G

  • Hardware - Processadores lógicos: 12. Memória física: 144GB.

  • Hardware - Configuração NUMA

    • Nó: 0 Estado: ONLINE Agendadores online: 4 Agendadores offline: 2 Grupo de processadores: 0 Nó de memória: 0 Memória VAS GB reservado: 186

    • Nó: 1 Estado: OFFLINE Agendadores online: 0 Agendadores offline: 6 Grupo de processadores: 0 Nó de memória: 0 Memória VAS GB reservado: 186

  • Inicialização instantânea de arquivo habilitada - a conta de serviço tem a permissão Executar tarefas de manutenção de volume.

  • Plano de energia - Seu servidor tem CPUs de 2,60 GHz e está no modo de energia balanceada -- Uh... você quer que suas CPUs funcionem em velocidade máxima, certo?

  • Última reinicialização do servidor - 9 de março de 2018 7h27

  • Nome do servidor - [redigido]

  • Serviços

    • Serviço: o SQL Server (MSSQLSERVER) é executado na conta de serviço NT Service\MSSQLSERVER. Última hora de inicialização: 9 de março de 2018 7h27. Tipo de inicialização: Automático, atualmente em execução.

    • Serviço: o SQL Server Agent (MSSQLSERVER) é executado na conta de serviço LocalSystem. Última hora de inicialização: não mostrada. Tipo de inicialização: Automático, atualmente em execução.

  • Última reinicialização do SQL Server - 9 de março de 2018 6h27

  • Serviço SQL Server - Versão: 13.0.4466.4. Nível de patch: SP1. Atualização cumulativa: $ 7. Edição: Edição padrão (64 bits). Grupos de Disponibilidade Habilitados: 0. Status do Gerente de Grupos de Disponibilidade: 2

  • Servidor Virtual - Tipo: (HIPERVISOR)

  • Versão do Windows - Você está executando uma versão bastante moderna do Windows: era do servidor 2012R2, versão 6.3

Prioridade 254: Data de execução :

  • Diário do capitão: stardate algo e algo...
sql-server performance
  • 3 respostas
  • 5881 Views
Martin Hope
PicoDeGallo
Asked: 2018-04-05 13:01:49 +0800 CST

A troca de IN com EXISTS produz diferentes conjuntos de resultados

  • 4

Estou tentando atualizar uma consulta que utiliza o INoperador dentro de um WHEREpredicado de cláusula EXISTSpara comparar possíveis melhorias de desempenho e entender melhor o que está acontecendo nos bastidores quando os dois são trocados. É meu entendimento que na prática, o otimizador de consultas trata EXISTSe INda mesma forma sempre que pode.

Estou percebendo que quando a consulta é executada com o INoperador, ela retorna o conjunto de resultados desejado. No entanto, quando eu o substituo pelo EXISTSequivalente, ele extrai todos os valores da tabela primária que quero filtrar. Ele está ignorando os valores de entrada fornecidos EXISTS (SELECT ...e retornando todos os valores distintos possíveis.

O caso de uso é relativamente simples: a consulta aceita uma string delimitada por barra vertical @Seriesque pode conter até 4 valores, por exemplo, S1|S2|S3|S4ou S2|S4. A partir daqui eu string_splita entrada em uma variável de tabela @SeriesSplitpara determinar o interno correspondente [SeriesId]para o arquivo [Series]. O conjunto de resultados retornado é então filtrado para excluir os [Series]que não foram passados.

Para ilustrar, aqui está uma definição de tabela semelhante:

DROP TABLE IF EXISTS [dbo].[Document]
IF OBJECT_ID('[dbo].[Document]', 'U') IS NULL
BEGIN
    CREATE TABLE [dbo].[Document] (
        [DocumentId] bigint IDENTITY(1,1) NOT NULL
        ,[DocumentSeriesId] [tinyint] NOT NULL
        ,CONSTRAINT [PK_Document] PRIMARY KEY CLUSTERED ([DocumentId] ASC)
        ,INDEX [IX_Document_SeriesId] NONCLUSTERED ([DocumentSeriesId] ASC)
    );
END;
GO

Preencha a tabela de teste com dados fictícios.

SET IDENTITY_INSERT [dbo].[Document] ON;
;WITH [DocumentSeed] AS (
    SELECT
        1 AS [DocumentId]
    UNION ALL
    SELECT
        [DocumentId] + 1
    FROM
        [DocumentSeed]
    WHERE
        [DocumentId] < 2048)

INSERT INTO [dbo].[Document] ([DocumentId], [DocumentSeriesId])
SELECT
    [DocumentId]
    ,ABS(CHECKSUM(NEWID()) % 4) + 1
FROM
    [DocumentSeed] OPTION (MAXRECURSION 2048);
SET IDENTITY_INSERT [dbo].[Document] OFF;

Primeiro, a consulta que utiliza o INoperador e retorna os resultados desejados.

-- Specify the Document Series to be returned.
DECLARE @Series varchar(12) = 'S1|S2'
-- Split the user input and insert it into a table variable.
DECLARE @SeriesSplit table ([SeriesId] tinyint, [Series] varchar(2))
BEGIN
INSERT INTO @SeriesSplit ([SeriesId], [Series])
SELECT
    CASE [value] WHEN 'S1' THEN 1 WHEN 'S2' THEN 2 WHEN 'S3' THEN 3 WHEN 'S4' THEN 4 ELSE 5 END AS [SeriesId]
    ,LTRIM(RTRIM([value])) AS [Series]
FROM
    string_split(@Series,'|')
WHERE
    [value] <> ''
END;

-- Return the result set of desired [DocumentSeriesId]
-- In the real use case, DISTINCT is not used and more columns are returned.
-- However, to illustrate the issue at hand, return only the [DocumentSeriesId] as this is what we are filtering off.
SELECT DISTINCT
    D1.[DocumentSeriesId]
FROM
    [dbo].[Document] D1
WHERE
    D1.[DocumentSeriesId] IN (SELECT SS.[SeriesId] FROM @SeriesSplit SS)

As saídas duas linhas conforme desejado. O plano de execução (PasteThePlan) mostra-o executando um Distinct Sortpara filtrar as linhas apropriadas.

Se eu alterar a WHEREcláusula para utilizar EXISTS, sou recebido com todos os quatro resultados possíveis , embora tenha definido para retornar apenas dois.

-- Specify the Document Series to be returned.
DECLARE @Series varchar(14) = 'S1|S2'
-- Split the user input and insert it into a table variable.
DECLARE @SeriesSplit table ([SeriesId] tinyint, [Series] varchar(4))
BEGIN
INSERT INTO @SeriesSplit ([SeriesId], [Series])
SELECT
    CASE [value] WHEN 'S1' THEN 1 WHEN 'S2' THEN 2 WHEN 'S3' THEN 3 WHEN 'S4' THEN 4 ELSE 5 END AS [SeriesId]
    ,LTRIM(RTRIM([value])) AS [Series]
FROM
    string_split(@Series,'|')
WHERE
    [value] <> ''
END;

-- Return the result set of desired [DocumentSeriesId]
-- In the real use case, DISTINCT is not used and more columns are returned.
-- However, to illustrate the issue at hand, return only the [DocumentSeriesId] as this is what we are filtering off.
SELECT DISTINCT
    D1.[DocumentSeriesId]
FROM
    [dbo].[Document] D1
WHERE
    EXISTS (SELECT SS.[SeriesId] FROM @SeriesSplit SS JOIN [dbo].[Document] D2 ON SS.[SeriesId] = D2.[DocumentSeriesId])

O plano de execução (PasteThePlan) é muito diferente com essa pequena alteração. É lançar um aviso de que existe No Join Predicatedentro do Left Semi Joinpredicado. Foi minha suposição que WHERE EXISTS ...satisfaria implicitamente esse argumento, como acontece com o WHERE [DocumentSeriesId] IN .... No entanto, dado que o Left Semi Joinoperador retorna cada linha da entrada inicial quando há uma linha correspondente na segunda entrada e porque o No Join Predicateaviso existe, o otimizador de consulta assume que cada linha é uma linha correspondente. Portanto, todas as operações em lote subsequentes são executadas em todas as 2.048 linhas da tabela.

O que posso analisar para interpretar melhor o que o plano de execução está descrevendo para que eu possa entender como resolver o problema adequadamente?

Ou, alternativamente, estou simplesmente perdendo o propósito do EXISTSoperador ao filtrar conjuntos de resultados com base em uma entrada estática?

sql-server performance
  • 1 respostas
  • 156 Views
Martin Hope
PicoDeGallo
Asked: 2018-03-28 06:59:25 +0800 CST

DATEADD não está produzindo uma expectativa SARGable de uma busca de índice

  • 7

Eu tenho uma [UserActivity]tabela básica que captura um ActivityTypeIdpor UserIde o ActivityDateem que a atividade ocorreu.

Estou escrevendo uma consulta/procedimento armazenado que permite a entrada do @UserId, @ForTypeId, bem como o @DurationIntervale @DurationIncrementpara retornar resultados dinamicamente com base no número N de segundos/minutos/horas/dias/meses/anos. Dado que o datepartargumento dentro DATEADD/DATEDIFFnão permite parâmetros, eu tive que reverter um pouco de truque para obter os resultados desejados dentro da WHEREcláusula.

Inicialmente escrevi a consulta usando DATEDIFF, mas imediatamente após escrever e dar uma olhada no plano de execução, lembrei que não é uma função SARGable (junto com o fato de que os níveis de precisão podem oferecer para algumas datas caindo em um ano bissexto). Então, eu reescrevi a consulta para utilizar DATEPARTo pensamento de que eu atingiria uma busca de índice em vez de uma varredura de índice e geralmente teria um desempenho melhor.

Infelizmente, descobri que escrever a consulta como DATEADDoferece os mesmos resultados: uma verificação de índice está ocorrendo e o otimizador de consulta não está aproveitando o índice não clusterizado em relação ao [ActivityDate].

Eu li a postagem no blog de Aaron Bertrand, "Performance Surprises and Assumptions: DATEADD" e implementei as mudanças que ele descreveu para CONVERTa DATEADDparte na datetime2definição de coluna equivalente devido a truques estranhos envolvidos com datetime2. No entanto, o problema ainda estava presente mesmo depois de fazê-lo.

Para ilustrar melhor o cenário, aqui está uma definição de tabela comparável.

DROP TABLE IF EXISTS [dbo].[UserActivity]
IF OBJECT_ID('[dbo].[UserActivity]', 'U') IS NULL
BEGIN
    CREATE TABLE [dbo].[UserActivity] (
        [UserId] [int] NOT NULL
        ,[UserActivityId] [bigint] IDENTITY(1,1) NOT NULL
        ,[ActivityTypeId] [tinyint] NOT NULL
        ,[ActivityDate] [datetime2](0) NOT NULL CONSTRAINT [DF_UserActivity_ActivityDate] DEFAULT GETDATE()
        ,CONSTRAINT [PK_UserActivity] PRIMARY KEY CLUSTERED ([UserActivityId] ASC)
        ,INDEX [IX_UserActivity_UserId] NONCLUSTERED ([UserId] ASC)
        ,INDEX [IX_UserActivity_ActivityTypeId] NONCLUSTERED ([ActivityTypeId] ASC)
        ,INDEX [IX_UserActivity_ActivityDate] NONCLUSTERED ([ActivityDate] ASC)
    )
END;
GO

Preencha a tabela com dados fictícios recursivamente para 5 usuários diferentes com um aleatório ActivityTypeIdentre 1 e 10 com um novo a ActivityDatecada 4 minutos.

DECLARE @UserId int = (SELECT ISNULL((SELECT TOP (1) [UserId] + 1 FROM [dbo].[UserActivity] ORDER BY [UserId] DESC), 1))
;WITH [UserActivitySeed] AS (
    SELECT
        CONVERT(datetime2(0), '01/01/2018') AS 'ActivityDate'
    UNION ALL
    SELECT
        DATEADD(minute, 4, [ActivityDate])
    FROM
        [UserActivitySeed]
    WHERE
        [ActivityDate] < '2018-04-01')
INSERT INTO [dbo].[UserActivity] ([UserId], [ActivityTypeId], [ActivityDate])
SELECT
    @UserId
    ,ABS(CHECKSUM(NEWID()) % 9) + 1
    ,[ActivityDate]
FROM
    [UserActivitySeed] OPTION (MAXRECURSION 32767);

GO 5

ALTER INDEX ALL ON [dbo].[UserActivity] REBUILD;

Abaixo está a primeira consulta que escrevi com DATEDIFF. Observe que estou excluindo os predicados @UserIde @ForTypeIdintencionalmente para evitar essas pesquisas de chave e reduzir o ruído nos planos anexados.

Como você encontrará em PasteThePlan para esta consulta , ele está realizando uma verificação de índice conforme o esperado, uma vez que DATEDIFFnão é SARGable.

DECLARE @UserId int = 1
DECLARE @ForTypeId int = 3
DECLARE @DurationInterval varchar(6) = 'hour'
DECLARE @DurationIncrement int = 1

SELECT
    COUNT(UA.[UserActivityId]) AS 'ActivityTypeCount'
FROM
    [dbo].[UserActivity] UA
WHERE
    -- Exclude the @UserId and @ForTypeId predicates.
    -- UA.[UserId] = @UserId
    -- AND UA.[ActivityTypeId] = @ForTypeId
    -- AND 
    CASE
        WHEN @DurationInterval IN ('year', 'yy', 'yyyy') THEN DATEDIFF(SECOND, UA.[ActivityDate], GETDATE()) / 3600.0 / 24.0 / 365.25
        WHEN @DurationInterval IN ('month', 'mm', 'm') THEN DATEDIFF(SECOND, UA.[ActivityDate], GETDATE()) / 3600.0 / 24.0 / 365.25 * 12
        WHEN @DurationInterval IN ('day', 'dd', 'd') THEN DATEDIFF(SECOND, UA.[ActivityDate], GETDATE()) / 3600.0 / 24.0
        WHEN @DurationInterval IN ('hour', 'hh') THEN DATEDIFF(SECOND, UA.[ActivityDate], GETDATE()) / 3600.0
        WHEN @DurationInterval IN ('minute', 'mi', 'n') THEN DATEDIFF(SECOND, UA.[ActivityDate], GETDATE()) / 60.0
        WHEN @DurationInterval IN ('second', 'ss', 's') THEN DATEDIFF(SECOND, UA.[ActivityDate], GETDATE())
    END < @DurationIncrement

Abaixo está a DATEADDconsulta. PasteThePlan aqui. Infelizmente, uma busca de índice não está ocorrendo. Esta pode ser uma suposição incorreta da minha parte, mas estou perplexo por que isso não está ocorrendo.

DECLARE @UserId int = 1
DECLARE @ForTypeId int = 3
DECLARE @DurationInterval varchar(6) = 'hour'
DECLARE @DurationIncrement int = 1

SELECT
    COUNT(UA.[UserActivityId]) AS 'ActivityTypeCount'
FROM
    [dbo].[UserActivity] UA
WHERE
    -- Exclude the @UserId and @ForTypeId predicates.
    -- UA.[UserId] = @UserId
    -- AND UA.[ActivityTypeId] = @ForTypeId
    -- AND 
    (
        (@DurationInterval IN ('year', 'yy', 'yyyy') AND UA.[ActivityDate] > CONVERT(datetime2(0), DATEADD(YEAR, -@DurationIncrement, GETDATE())))
        OR
        (@DurationInterval IN ('month', 'mm', 'm') AND UA.[ActivityDate] > CONVERT(datetime2(0), DATEADD(MONTH, -@DurationIncrement, GETDATE())))
        OR
        (@DurationInterval IN ('day', 'dd', 'd') AND UA.[ActivityDate] > CONVERT(datetime2(0), DATEADD(DAY, -@DurationIncrement, GETDATE())))
        OR
        (@DurationInterval IN ('hour', 'hh') AND UA.[ActivityDate] > CONVERT(datetime2(0), DATEADD(HOUR, -@DurationIncrement, GETDATE())))
        OR
        (@DurationInterval IN ('minute', 'mi', 'n') AND UA.[ActivityDate] > CONVERT(datetime2(0), DATEADD(MINUTE, -@DurationIncrement, GETDATE())))
        OR
        (@DurationInterval IN ('second', 'ss', 's') AND UA.[ActivityDate] > CONVERT(datetime2(0), DATEADD(SECOND, -@DurationIncrement, GETDATE())))
        )

Qual é a causa disso? O comportamento que estou vendo é resultado do meu uso de ORnegação de qualquer potencial para que ele chegue a usar o índice? Estou ignorando algo meticulosamente óbvio aqui?

ATUALIZAÇÃO: Minha segunda pergunta acima me levou a realizar uma consulta anterior às ORoperações. A consulta executou a busca de índice, então algo está ocorrendo durante essas comparações que o SQL Server não gosta. PasteThePlan aqui.

DECLARE @DurationIncrement int = 1

SELECT
    COUNT(UA.[UserActivityId]) AS 'ActivityTypeCount'
FROM
    [dbo].[UserActivity] UA
WHERE
    UA.[ActivityDate] > CONVERT(datetime2(0), DATEADD(HOUR, -@DurationIncrement, GETDATE()))

ATUALIZAÇÃO: Solução compartilhada aqui.

sql-server index
  • 4 respostas
  • 908 Views
Martin Hope
PicoDeGallo
Asked: 2018-03-20 06:40:40 +0800 CST

Tabela com índice clusterizado classificando implicitamente por índice não clusterizado exclusivo

  • 4

Eu tenho uma tabela que captura a plataforma host em que um usuário está executando. A definição da tabela é simples:

IF OBJECT_ID('[Auth].[ActivityPlatform]', 'U') IS NULL
BEGIN
    CREATE TABLE [Auth].[ActivityPlatform] (
        [ActivityPlatformId] [tinyint] IDENTITY(1,1) NOT NULL
        ,[ActivityPlatformName] [varchar](32) NOT NULL
        ,CONSTRAINT [PK_ActivityPlatform] PRIMARY KEY CLUSTERED ([ActivityPlatformId] ASC)
        ,CONSTRAINT [UQ_ActivityPlatform_ActivityPlatformName] UNIQUE NONCLUSTERED ([ActivityPlatformName] ASC)
    ) ON [Auth];
END;
GO

Os dados que ele armazena são enumerados com base em um método JavaScript que usa informações do navegador (não sei muito mais do que isso, mas posso descobrir se necessário):

Plataformas

Quando eu executo um basic SELECTsem um explicit ORDER BY, porém, o Execution Plan mostra que está usando o UNIQUE NONCLUSTEREDíndice para ordenar ao invés do CLUSTEREDíndice.

SELECT * FROM [Auth].[ActivityPlatform] 

Cache não clusterizado

Ao especificar explicitamente o ORDER BY, ele classifica corretamente por ActivityPlatformId.

SELECT * FROM [Auth].[ActivityPlatform] ORDER BY [ActivityPlatformId]

ClusteredCache

DBCC SHOWCONTIG('[Auth].[ActivityPlatform]') WITH ALL_LEVELS, TABLERESULTSnão mostra nenhuma fragmentação de tabela.

O que estou perdendo que poderia causar isso? Eu pensei tanto que a tabela foi criada em um índice clusterizado, ela deveria classificar automaticamente por ela implicitamente sem a necessidade de especificar ORDER BY. Qual a preferência do SQL Server na escolha do UQ? Existe algo que eu preciso especificar na criação da tabela?

sql-server index
  • 1 respostas
  • 1353 Views
Martin Hope
PicoDeGallo
Asked: 2018-02-27 15:20:07 +0800 CST

Alterando funções de partição dinamicamente usando gatilhos

  • 1

Estou querendo utilizar o particionamento com base em um [TenantId](e posteriormente em conjunto com intervalos de datas). Em vez de precisar inserir manualmente o valor mais recente dentro do PARTITION FUNCTION, pensei em criar um TRIGGER AFTER INSERTpara puxar o [TenantId]valor e ALTER PARTITION FUNCTIONadicioná-lo ao SPLIT RANGE. No entanto, estou me deparando com um erro inesperado:

Não é possível executar ALTER PARTITION FUNCTION na/usando a tabela 'Tenant', pois a tabela é a tabela de destino ou parte das ações em cascata de um gatilho atualmente em execução.

Primeiro, estou criando o PARTITION FUNCTION [PF_Tenant_Isolation]and PARTITION SCHEME [PS_Tenant_Isolation]para particionamento no [TenantId].

CREATE PARTITION FUNCTION [PF_Tenant_Isolation] ([int])
    AS RANGE LEFT FOR VALUES (1);
GO

CREATE PARTITION SCHEME [PS_Tenant_Isolation]
    AS PARTITION [PF_Tenant_Isolation]
    ALL TO ([Auth]);
GO

Depois disso, estou criando a [Tenant]tabela no esquema de partição recém-criado.

IF OBJECT_ID('[Auth].[Tenant]', 'U') IS NULL
BEGIN
    CREATE TABLE [Auth].[Tenant] (
        [TenantId] [int] IDENTITY(1,1)
        ,[TenantActive] [bit] NOT NULL CONSTRAINT [DF_Tenant_TenantActive] DEFAULT 1
        ,[TenantName] [varchar](256) NOT NULL
        ,CONSTRAINT [PK_Tenant_TenantId] PRIMARY KEY CLUSTERED ([TenantId] ASC)
    ) ON [PS_Tenant_Isolation]([TenantId]);
END

Eu semeio o primeiro valor antes de criar o gatilho.

INSERT INTO [Auth].[Tenant]
VALUES (1,'Partition Trigger Test A');

Eu crio o gatilho na tabela [Tenant].

CREATE TRIGGER [TR_Tenant_Isolation] ON [Auth].[Tenant]
AFTER INSERT
AS
BEGIN
    DECLARE @MaxInsertedId int
    SET @MaxInsertedId = (SELECT MAX([TenantId]) FROM inserted)

    ALTER PARTITION SCHEME [PS_Tenant_Isolation]
        NEXT USED [Auth];

    ALTER PARTITION FUNCTION [PF_Tenant_Isolation]()
        SPLIT RANGE (@MaxInsertedId);
END

Eu sigo isso com a tentativa de inserir o segundo [Tenant]valor.

INSERT INTO [Auth].[Tenant]
VALUES (1,'Partition Trigger Test B');

É quando o erro descrito acima aparece. Com base no erro em si, lendo os argumentos do Technet , entendo que o problema está na utilização do AFTER INSERT. Como a ação de partição da transação depende da utilização do valor de intervalo dentro da função de partição, a ALTER PARTITION SCHEMEfalha e, portanto, toda a transação também.

AFTER especifica que o gatilho DML é acionado somente quando todas as operações especificadas na instrução SQL de gatilho forem executadas com êxito. Todas as ações referenciais em cascata e verificações de restrição também devem ser bem-sucedidas antes que esse gatilho seja acionado.

Eu olhei em INSTEAD OF INSERT , mas não tive nenhum sucesso. O gatilho é acionado uma vez e atualiza o SPLIT RANGEcom um valor de 0 (convertido implicitamente de NULL). Acredito que isso se deva ao fato de IDENTITYnão estar devidamente capturado no escopo da transação.

CREATE TRIGGER [TR_Tenant_Isolation] ON [Auth].[Tenant]
INSTEAD OF INSERT
AS
BEGIN
    DECLARE @MaxInsertedId int
    SET @MaxInsertedId =  (SELECT [TenantId] FROM inserted)

    ALTER PARTITION SCHEME [PS_Tenant_Isolation]
        NEXT USED [Auth];

    ALTER PARTITION FUNCTION [PF_Tenant_Isolation]()
        SPLIT RANGE (@MaxInsertedId);

    INSERT INTO [Auth].[Tenant] ([TenantActive], [TenantName])
    SELECT [TenantActive], [TenantName]
    FROM inserted;
END

As inserções de linhas subsequentes [Tenant]produzem um erro adicional devido à tentativa de inserir 0 (NULL).

Valores de limite de intervalo duplicados não são permitidos na lista de valores de limite de função de partição. O valor de limite que está sendo adicionado já está presente no ordinal 1 da lista de valores de limite.

Como posso contornar isso? Preciso definir explicitamente o IDENTITYvalor de [TenantId]em conjunto com INSTEAD OF INSERT? Novas inserções em [Tenant]serão bastante esporádicas e mínimas, mas [TenantId]serão uma chave restritiva em outras tabelas. É por isso que decidi investigar esse método de implementação para alterar dinamicamente a função de partição.

sql-server database-design
  • 1 respostas
  • 2377 Views
Martin Hope
PicoDeGallo
Asked: 2018-02-23 06:47:19 +0800 CST

Índices únicos ou múltiplos não clusterizados ao emparelhar com uma chave primária composta

  • 1

Eu tenho um banco de dados em que estou utilizando um TenantIdem todas as tabelas que precisam ser identificadas exclusivamente para um inquilino específico e, devido aos requisitos de ordenação nas chaves compostas, tenho TenantIdcomo o primeiro na lista de índices. Agora entra em questão uma Authenticationpeça onde a Usertabela contém o TenantId, UserId(a IDENTITYcoluna), e Emailentre outros itens específicos de login.

O portal de login não é específico do locatário, portanto, ao fazer login, o usuário simplesmente inserirá seu Email, buscando assim a linha que verifica suas informações de login. Nesse cenário, não podemos aproveitar imediatamente a chave primária composta de TenantIde UserIdaté encontrarmos a linha que se aplica a Email.

A chave primária composta em TenantIde sempreUserId será utilizada em todas as outras cláusulas condicionais. No entanto, para aproveitar essa chave em primeiro lugar, devemos primeiro procurar essa linha com base em uma consulta de . Sem um índice em , uma verificação de tabela ocorrerá.EmailEmail

Minha pergunta é, que tipo de combinação de índice seria visto como mais adequado neste cenário? Um único índice não clusterizado Emailsozinho, outra chave composta em UserIde Emailem conjunto com o único índice não clusterizado Emailcom INCLUDES em outros dados relevantes, ou nenhuma das opções acima?

O esquema é semelhante assim:

CREATE TABLE [User] (
     [TenantId] [int] NOT NULL
    ,[UserId] [int] IDENTITY(1,1) NOT NULL
    ,[Email] [varchar](64) NOT NULL
    ,[FirstName] [varchar](32) NOT NULL
    ,[MiddleName] [varchar](32) NULL
    ,[LastName] [varchar](32) NOT NULL
    ,[PasswordHash] [varbinary](64) NOT NULL
    ,[PasswordSalt] [varbinary](32) NOT NULL
    ,[HashMethodId] [tinyint] NOT NULL
    ,[IsActive] [bit] NOT NULL CONSTRAINT [DF_User_IsActive] DEFAULT 1
    ,[IsLocked] [bit] NOT NULL CONSTRAINT [DF_User_IsLocked] DEFAULT 0

    ,CONSTRAINT [PK_User_TenantId_UserId] PRIMARY KEY CLUSTERED ([TenantId] ASC, [UserId] ASC)
    ,INDEX [IX_User_UserId_Email] NONCLUSTERED ([UserId] ASC, [Email] ASC)
    ,CONSTRAINT [FK_Tenant_TenantId] FOREIGN KEY ([TenantId]) REFERENCES [Tenant]([TenantId])
    ,CONSTRAINT [FK_HashMethod_HashMethodId] FOREIGN KEY ([HashMethodId]) REFERENCES [HashMethod]([HashMethodId])
);
CREATE NONCLUSTERED INDEX [IX_User_Email] ON [User]([Email]) INCLUDE ([PasswordHash],[PasswordSalt],[HashMethodId],[IsActive],[IsLocked])

-- Note for research: Why can an index that has INCLUDE not be specified in CREATE TABLE?

Meu entendimento é que [IX_User_UserId_Email]é útil neste cenário ligar rapidamente para [PK_User_TenantId_UserId], buscando assim o nível adequado de isolamento de forma mais eficiente. Essa é uma suposição incorreta? Estou melhor servido usando apenas [IX_User_Email]?

  • Todas as tabelas irão JOIN para Useron TenantIde UserId.
  • Nenhuma tabela será estritamente JOIN com Userbase em UserId.
  • Uma pesquisa acontecerá com base estritamente em uma consulta de Email. TenantIde UserIdnão será conhecido até que a linha seja buscada. Depois que a linha for buscada, as consultas restantes utilizarão TenantIde UserId.

Outra opção que tenho usado está dentro da Tenanttabela, incluindo uma Domaincoluna que especifica o domínio de email de origem do locatário (que sempre será o mesmo em um locatário). Uma vez que o usuário tenha inserido seu Emaile tabulado/selecionado o Passwordcampo na página de login, ele analisará o domínio de e-mail ( @sample.com), permitindo-nos consultar a Tenanttabela menor para encontrar seu TenantId, podendo assim aproveitar a chave composta [PK_User_TenantId_UserId]e, assim, apenas ter que utilizar um índice não clusterizado no Email. Esta pode ser uma abordagem desnecessária, no entanto.

sql-server database-design
  • 3 respostas
  • 733 Views
Martin Hope
PicoDeGallo
Asked: 2017-12-06 13:01:39 +0800 CST

SQL Server 2016 ISNULL Retornando 1900-01-01

  • 3

Eu tenho uma datetime2coluna chamada DocDateque estou tentando avaliar uma ISNULLverificação para retornar um ''valor em branco para em vez de NULL.

Um trecho da declaração:

SELECT TOP 100
    DocumentId
    ,DocDate
    ,ISNULL(DocDate,'') AS 'DocDateEmpty'
FROM
    DocDetails
WHERE
    DocDate IS NULL

Isso retorna:1900-01-01 00:00:00.0000000

Minha WHEREcláusula claramente traz de volta apenas as linhas que são explicitamente NULL, então não é uma questão de DocDateser uma string vazia e avaliar para 0.

Captura de SSMS

Como pode DocDate IS NULLavaliar corretamente, mas ISNULLfalha?

Por MSDN , ISNULLdeve avaliar o valor literal NULL corretamente e retornar um valor vazio.

Retorna o mesmo tipo que check_expression . Se um literal NULL for fornecido como check_expression , retornará o tipo de dados do valor_substituição . Se um literal NULL for fornecido como check_expression e nenhum valor_substituição for fornecido, retornará um int .

sql-server t-sql
  • 1 respostas
  • 5943 Views
Martin Hope
PicoDeGallo
Asked: 2017-04-05 11:07:07 +0800 CST

Velocidade do clock da CPU versus contagem de núcleos da CPU - GHz mais alto ou mais núcleos para o SQL Server?

  • 36

Estamos começando a provisionar um conjunto de servidores físicos para um cluster virtual de nós do SQL Server 2016 no VMware. Estaremos utilizando licenças Enterprise Edition.

Planejamos configurar 6 nós, mas há um pouco de debate sobre qual a maneira ideal de provisionar os servidores físicos com relação à velocidade do clock da CPU versus a contagem de núcleos da CPU.

Eu sei que isso depende em grande parte do volume de transações e do número de bancos de dados armazenados entre outros fatores específicos do software, mas há uma regra geral recomendada?

Por exemplo, um servidor físico duplo de 8 núcleos e 3,2 GHz (16 núcleos) é mais preferencial do que um servidor duplo de 16 núcleos e 2,6 GHz (32 núcleos)?

Alguém já se deparou com um white paper que aprofunde esse tipo de tópico?

sql-server performance
  • 4 respostas
  • 25316 Views
Martin Hope
PicoDeGallo
Asked: 2017-02-23 16:17:56 +0800 CST

Suprimir avisos e mensagens de log específicos do SQL Server

  • 4

Desejo minimizar a saída de determinados avisos e mensagens nos logs do SQL Server 2012, como quando um spid é eliminado. Não consigo encontrar informações sobre como suprimir/expandir quais mensagens são realmente enviadas para os logs de erros. Isso é feito por meio de sinalizadores de rastreamento?

Estou tentando reduzir o número de avisos em nosso servidor de banco de dados de desenvolvimento e restringi-lo a erros legítimos. Temos desenvolvedores matando spids ou liberando o cache de consulta para ajuste de desempenho (jogando com ajuste de índice, forçando a contenção intencional de tabela, criando deadlocks etc.), em vários bancos de dados no mesmo servidor. Ter um arquivo de log preenchido com esses avisos é apenas um incômodo que eu queria ver se era possível suprimir.

sql-server logging
  • 1 respostas
  • 1192 Views
Martin Hope
PicoDeGallo
Asked: 2016-08-24 12:12:59 +0800 CST

Crescimento automático por MB em vez de porcentagem

  • 1

Depois de mergulhar no crescimento automático e nas práticas recomendadas em torno dele (principalmente ser proativo e ajustar os tamanhos dos grupos de arquivos com antecedência), havia uma pergunta iminente para a qual não encontrei uma resposta completa. A maioria dos artigos, incluindo o TechNet, sempre menciona a prática de definir o Autogrowth para 10-15% como uma falha segura. Parece haver menção mínima de utilizar a opção de crescimento MB como uma falha segura.

Digamos, por exemplo, que você tenha um tamanho de banco de dados atual de 500 GB com um crescimento de arquivo de aproximadamente ~ 1 GB / dia, mais ou menos algumas centenas de MB. A cada fim de semana, você ajusta os grupos de arquivos necessários em uma quantidade X para cobrir o crescimento - digamos, aumentando-o para 540 GB para cobrir quase um mês de crescimento. Caso você não consiga ajustá-lo quando atingir 540 GB (simplesmente esquecido, expansão inesperada da tabela etc.), o MSSQL entra em ação e tenta aumentar o banco de dados em 15%, mas acaba com um tempo limite contínuo porque o valor do crescimento é muito grande para o servidor manipular automaticamente. Isso causa tempo limite do aplicativo e, portanto, a intervenção manual é necessária independentemente.

Trago isso à tona porque, nos testes, o crescimento automático por porcentagem parece oferecer tempos limite nesses casos de teste. No entanto, se eu definir o crescimento automático para um MB definido, por exemplo, 1.000 MB, ele aumentará sem nenhum problema e o fará em tempo hábil.

Portanto, para resumir minha pergunta, por que os artigos (pelo menos os que li) seguem a prática de utilizar o Autogrowth por porcentagem em vez do Autogrowth por MB no caso de o crescimento manual proativo do arquivo não ter ocorrido? Parece-me que em testes e em teoria, você prefere que o Autogrow ajuste por um valor definido em MB.

Sou falso nesse pensamento ou estou apenas lendo as coisas erradas? Seria ótimo saber que tipo de técnicas administrativas vocês utilizam aqui.

Obrigado!

sql-server sql-server-2012
  • 1 respostas
  • 2705 Views
Martin Hope
PicoDeGallo
Asked: 2015-11-24 18:09:34 +0800 CST

Extração de dados com vários delimitadores?

  • 3

Eu tenho uma coluna de fonte de dados herdada delimitada por ponto-e-vírgula e vírgula. O primeiro ponto e vírgula indica o sobrenome, o segundo indica o nome e o nome do meio (ou iniciais) e o último ponto e vírgula indica o tipo de indivíduo. A vírgula indica que um novo nome começou. Aqui está uma amostra desses dados.

+-------+---------------------------------------------------------------------------------------------------------------------+
|  ID   | SOURCE                                                                                                              |
+-------+---------------------------------------------------------------------------------------------------------------------+
| 62963 | RENZ;MICHAEL;DECEASED,WANDER;MARIA;MINOR,WANDER;HENRY RUDOLPH;MINOR,WANDER;ROSA;MINOR,WANDER;PAUL EMIL;MINOR        |
| 62964 | HERNDON;A C;ESTATE,BERRING;A F;DECEASED,BEIRING;A F;DECEASED,BEIRING;ANDREAS FREDERICK;DECEASED                     |
| 62965 | ZINCH;;ESTATE,ZINTZ;;ESTATE,HAYNES;HENRY;DECEASED                                                                   |
| 62965 | ZINCH;;ESTATE,ZINTZ;;ESTATE,HAYNES;HENRY;DECEASED                                                                   |
| 62966 | KRAUS;JOSEPHINE;MINOR,KENNEDY;GEORGE;DECEASED                                                                       |
| 62967 | CAREY;JAMES;ESTATE,DE LA GARZA;REFUGIO;DECEASED                                                                     |
| 62968 | LEWIS;FLORENCE;ESTATE,LOCKWOOD;ALBERT A;DECEASED                                                                    |
| 62969 | GLAESER;EMMA;MINOR,GLAESER;HERMAN JR;MINOR,GLAESER;HERMAN;MINOR,RODRIGUEZ;HILARIO;DECEASED,RODRIGUEZ;MARIE;DECEASED |
| 62970 | STORY;BETTIE;ESTATE,EIGENDORFF;FRANZ;DECEASED                                                                       |
| 62971 | HOWELL;MAMIE;MINOR,HOWELL;ETHEL;MINOR                                                                               |
+-------+---------------------------------------------------------------------------------------------------------------------+

Estou tentando extrair os dados de uma maneira como esta para que possam ser adaptados a um esquema diferente:

+-----------+------------+-------------+-------------------+----------+
|      ID   |   SEQUENCE |    LAST     |    FIRSTMIDDLE    |   TYPE   |
+-----------+------------+-------------+-------------------+----------+
|     62963 |          1 | RENZ        | MICHAEL           | DECEASED |
|     62963 |          2 | WANDER      | MARIA             | MINOR    |
|     62963 |          3 | WANDER      | HENRY RUDOLPH     | MINOR    |
|     62963 |          4 | WANDER      | ROSA              | MINOR    |
|     62963 |          5 | WANDER      | PAUL EMIL         | MINOR    |
|     62964 |          1 | HERNDON     | A C               | ESTATE   |
|     62964 |          2 | BERRING     | A F               | DECEASED |
|     62964 |          3 | BEIRING     | A F               | DECEASED |
|     62964 |          4 | BEIRING     | ANDREAS FREDERICK | DECEASED |
|     62965 |          1 | ZINCH       |                   | ESTATE   |
|     62965 |          2 | ZINTZ       |                   | ESTATE   |
|     62965 |          3 | HAYNES      | HENRY             | DECEASED |
|     62966 |          1 | KRAUS       | JOSEPHINE         | MINOR    |
|     62966 |          2 | KENNEDY     | GEORGE            | DECEASED |
|     62967 |          1 | CAREY       | JAMES             | ESTATE   |
|     62967 |          2 | DE LA GARZA | REFUGIO           | DECEASED |
|     62968 |          1 | LEWIS       | FLORENCE          | ESTATE   |
|     62968 |          2 | LOCKWOOD    | ALBERT A          | DECEASED |
|     62969 |          1 | GLAESER     | EMMA              | MINOR    |
|     62969 |          2 | GLAESER     | HERMAN JR         | MINOR    |
|     62969 |          3 | GLAESER     | HERMAN            | MINOR    |
|     62969 |          4 | RODRIGUEZ   | HILARIO           | DECEASED |
|     62969 |          5 | RODRIGUEZ   | MARIE             | DECEASED |
|     62970 |          1 | STORY       | BETTIE            | ESTATE   |
|     62970 |          2 | EIGENDORFF  | FRANZ             | DECEASED |
|     62971 |          1 | HOWELL      | MAMIE             | MINOR    |
|     62971 |          2 | HOWELL      | ETHEL             | MINOR    |
+-----------+------------+-------------+-------------------+----------+

Esse tipo de extração de dados é algo com o qual não estou muito familiarizado. Estou pensando que preciso usar uma combinação complexa de SUBSTRINGe CHARINDEX, mas como o número de entradas que a coluna de origem pode conter varia, não tenho certeza da melhor forma de abordar isso. Qualquer orientação sobre por onde devo começar seria incrivelmente útil.

sql-server t-sql
  • 2 respostas
  • 2960 Views
Martin Hope
PicoDeGallo
Asked: 2015-10-02 12:46:16 +0800 CST

Backups completos semanais e backups diferenciais diários, salvando os backups completos de cada semana?

  • 3

Estou querendo criar um plano de manutenção que faça um backup completo que é feito todo domingo de manhã. Após o expediente de segunda a sexta-feira, desejo realizar um backup diferencial com base neste backup completo. No entanto, em vez de sobrescrever o backup completo da semana anterior, quero reter esse backup completo para registros históricos/fora do local, ao mesmo tempo em que me livro dos diferenciais associados a esse backup completo. O tipo de plano que estou planejando criar é o seguinte:

  • Se necessário, uma reconstrução dos índices do banco de dados é feita no início da manhã de domingo.
    • Uma advertência adicional a isso seria reorganizar + atualizar as estatísticas com base na quantidade de fragmentação presente.
  • Após a manutenção do índice, um backup completo é criado na mesma manhã.
  • De segunda a sexta à noite, um backup diferencial é feito com base no backup completo.
  • Após o diferencial, uma verificação de integridade do banco de dados é executada.
  • No próximo domingo chega, um backup completo é estabelecido, os diferenciais da semana anterior removidos e o backup completo anterior é trazido aqui localmente para um Drobo após o expediente.

O motivo desse tipo de plano se deve às restrições de tamanho do HDD no ambiente do Azure com o qual estou trabalhando. Diante disso, essa é uma estratégia sólida ou onde devo buscar melhorias? Em segundo lugar, como retenho os backups completos do banco de dados da semana anterior, mas NÃO os diferenciais? Os artigos que li até agora parecem indicar que um backup rotativo dessa natureza terá os backups completos e diferenciais removidos.

Esta é uma instância do SQL Server 2012 em uma VM do Windows Server 2012 no ambiente Azure. Existem 5 bancos de dados, variando de 6 GB a 10 GB cada, que serão afetados por esse tipo de plano.

Obrigado pela sua assistência.

sql-server backup
  • 1 respostas
  • 2749 Views
Martin Hope
PicoDeGallo
Asked: 2015-06-02 07:56:09 +0800 CST

Função RIGHT () retornando resultado em branco

  • 1

Eu tenho uma única coluna que contém informações que preciso dividir em três colunas separadas. Atualmente, tenho uma instrução SELECT que funciona parcialmente, mas minha coluna ChangeTo não está retornando nenhum dado e não consigo descobrir por que. Aqui está a aparência da coluna atual que está sendo retornada:

| bp_comment                                             |
----------------------------------------------------------
| changed status from "new" to "in progress"             |
| changed ORT status from "in progress" to "Code Review" |
| changed MileStone from "1.1" to "1.2"                  |

Aqui estão como eu preciso que os resultados retornem:

| ChangeType              |  ChangeFrom  |   ChangeTo  |
-----------------------------------------------------
| changed status from     | new          | in progress |
| changed ORT status from | in progress  | Code Review |
| changed MileStone from  | 1.1          | 1.2         |

Aqui estão como os resultados estão retornando agora:

| ChangeType              |  ChangeFrom  |   ChangeTo  |
-----------------------------------------------------
| changed status from     | new          |             |
| changed ORT status from | in progress  |             |
| changed MileStone from  | 1.1          |             |

Aqui está a consulta que estou usando:

SELECT
    LEFT(CONVERT(VARCHAR(MAX), bp.bp_comment), CHARINDEX(' from ', CONVERT(VARCHAR(MAX), bp.bp_comment)) + 5) AS 'ChangeType'
    ,REPLACE(SUBSTRING(CONVERT(VARCHAR(MAX), bp.bp_comment), CHARINDEX(' from ', CONVERT(VARCHAR(MAX), bp.bp_comment)) + 5, CHARINDEX(' to ', CONVERT(VARCHAR(MAX), bp.bp_comment)) - CHARINDEX(' from ', CONVERT(VARCHAR(MAX), bp.bp_comment)) - 5), '"', '') AS 'ChangeFrom'
    ,REPLACE(RIGHT(CONVERT(VARCHAR(MAX), bp.bp_comment), CHARINDEX(' to ', REVERSE(CONVERT(VARCHAR(MAX), bp.bp_comment)))), '"', '') AS 'ChangeTo'
FROM
    bug_posts bp

Agradeço antecipadamente!

sql-server
  • 2 respostas
  • 962 Views

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve