Como varchar
de qualquer maneira aloca espaço dinamicamente, minha pergunta é se o uso varchar(255)
é mais eficiente ou economiza mais espaço em comparação ao uso do varchar(5000)
. Se sim, por quê?
Se eu tiver uma UPDATE
declaração que na verdade não altera nenhum dado (porque os dados já estão no estado atualizado). Existe algum benefício de desempenho em colocar uma verificação na WHERE
cláusula para evitar a atualização?
Por exemplo, haveria alguma diferença na velocidade de execução entre UPDATE 1 e UPDATE 2 no seguinte:
CREATE TABLE MyTable (ID int PRIMARY KEY, Value int);
INSERT INTO MyTable (ID, Value)
VALUES
(1, 1),
(2, 2),
(3, 3);
-- UPDATE 1
UPDATE MyTable
SET
Value = 2
WHERE
ID = 2
AND Value <> 2;
SELECT @@ROWCOUNT;
-- UPDATE 2
UPDATE MyTable
SET
Value = 2
WHERE
ID = 2;
SELECT @@ROWCOUNT;
DROP TABLE MyTable;
O motivo pelo qual pergunto é que preciso que a contagem de linhas inclua a linha inalterada para saber se devo fazer uma inserção se o ID não existir. Como tal, usei o formulário UPDATE 2. Se houver um benefício de desempenho ao usar o formulário UPDATE 1, é possível obter a contagem de linhas que preciso de alguma forma?
Tecnicamente, NULL = NULL é False, por essa lógica nenhum NULL é igual a qualquer NULL e todos os NULLs são distintos. Isso não deveria implicar que todos os NULLs são únicos e um índice único deve permitir qualquer número de NULLs?
Eu estava experimentando índices para acelerar as coisas, mas no caso de uma junção, o índice não está melhorando o tempo de execução da consulta e, em alguns casos, está diminuindo a velocidade.
A consulta para criar a tabela de teste e preenchê-la com dados é:
CREATE TABLE [dbo].[IndexTestTable](
[id] [int] IDENTITY(1,1) PRIMARY KEY,
[Name] [nvarchar](20) NULL,
[val1] [bigint] NULL,
[val2] [bigint] NULL)
DECLARE @counter INT;
SET @counter = 1;
WHILE @counter < 500000
BEGIN
INSERT INTO IndexTestTable
(
-- id -- this column value is auto-generated
NAME,
val1,
val2
)
VALUES
(
'Name' + CAST((@counter % 100) AS NVARCHAR),
RAND() * 10000,
RAND() * 20000
);
SET @counter = @counter + 1;
END
-- Index in question
CREATE NONCLUSTERED INDEX [IndexA] ON [dbo].[IndexTestTable]
(
[Name] ASC
)
INCLUDE ( [id],
[val1],
[val2])
Agora a consulta 1, que foi melhorada (apenas um pouco, mas a melhoria é consistente) é:
SELECT *
FROM IndexTestTable I1
JOIN IndexTestTable I2
ON I1.ID = I2.ID
WHERE I1.Name = 'Name1'
Estatísticas e plano de execução sem índice (neste caso, a tabela usa o índice clusterizado padrão):
(5000 row(s) affected)
Table 'IndexTestTable'. Scan count 2, logical reads 5580, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 109 ms, elapsed time = 294 ms.
Agora com o índice ativado:
(5000 row(s) affected)
Table 'IndexTestTable'. Scan count 2, logical reads 2819, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 94 ms, elapsed time = 231 ms.
Agora, a consulta que fica mais lenta devido ao índice (a consulta não tem sentido, pois é criada apenas para teste):
SELECT I1.Name,
SUM(I1.val1),
SUM(I1.val2),
MIN(I2.Name),
SUM(I2.val1),
SUM(I2.val2)
FROM IndexTestTable I1
JOIN IndexTestTable I2
ON I1.Name = I2.Name
WHERE
I2.Name = 'Name1'
GROUP BY
I1.Name
Com o índice clusterizado ativado:
(1 row(s) affected)
Table 'IndexTestTable'. Scan count 4, logical reads 60, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 1, logical reads 155106, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 17207 ms, elapsed time = 17337 ms.
Agora com o Index desabilitado:
(1 row(s) affected)
Table 'IndexTestTable'. Scan count 5, logical reads 8642, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 2, logical reads 165212, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
(1 row(s) affected)
SQL Server Execution Times:
CPU time = 17691 ms, elapsed time = 9073 ms.
As perguntas são:
- Mesmo que o índice seja sugerido pelo SQL Server, por que ele retarda as coisas por uma diferença significativa?
- Qual é a junção Nested Loop que está demorando mais e como melhorar seu tempo de execução?
- Há algo que estou fazendo de errado ou deixei passar?
- Com o índice padrão (somente na chave primária), por que leva menos tempo e com o índice não clusterizado presente, para cada linha na tabela de junção, a linha da tabela unida deve ser encontrada mais rapidamente, porque a junção está na coluna Nome na qual o índice foi criado. Isso se reflete no plano de execução da consulta e o custo de Index Seek é menor quando o IndexA está ativo, mas por que ainda mais lento? Além disso, o que está na junção externa esquerda do loop aninhado que está causando a lentidão?
Usando o SQLServer 2012
Tenho algumas tabelas muito grandes com a mesma estrutura básica. Cada um tem uma coluna RowNumber (bigint)
e . DataDate (date)
Os dados são carregados usando SQLBulkImport todas as noites e nenhum dado "novo" é carregado - é um registro histórico (SQL Standard, não Enterprise, portanto, sem particionamento).
Como cada bit de dados precisa ser vinculado a outros sistemas e cada RowNumber/DataDate
combinação é única, essa é minha chave primária.
Percebo que pela forma como defini o PK no SSMS Table Designer, RowNumber
está listado primeiro e DataDate
segundo.
Também noto que minha fragmentação é sempre MUITO alta ~ 99%.
Agora, como cada um DataDate
aparece apenas uma vez, eu esperaria que o indexador apenas adicionasse às páginas todos os dias, mas me pergunto se ele realmente está indexando com base no RowNumber
primeiro e, portanto, tendo que mudar todo o resto?
Rownumber
não é uma coluna de identidade, é um int gerado por um sistema externo (infelizmente). Ele redefine no início de cada DataDate
.
Dados de Exemplo
RowNumber | DataDate | a | b | c.....
1 |2013-08-01| x | y | z
2 |2013-08-01| x | y | z
...
1 |2013-08-02| x | y | z
2 |2013-08-02| x | y | z
...
Os dados estão sendo carregados em RowNumber
ordem, um DataDate
por carregamento.
O processo de importação é bcp - tentei carregar em uma tabela temporária e, em seguida, selecionar em ordem a partir daí ( ORDER BY RowNumber, DataDate
), mas ainda sai alta fragmentação.
Quando executo este SQL:
USE ASPState
GO
IF NOT EXISTS(SELECT * FROM sys.sysusers WHERE NAME = 'R2Server\AAOUser')
CREATE USER [R2Server\AAOUser] FOR LOGIN [R2Server\AAOUser];
GO
Estou tendo o erro a seguir:
O login já tem uma conta com um nome de usuário diferente.
Como posso saber qual é esse nome de usuário diferente para minha conta de login?
Estou tentando entender melhor as diferenças entre os comandos DELETE
e . TRUNCATE
Minha compreensão dos internos é algo como:
DELETE
-> o mecanismo de banco de dados encontra e remove a linha das páginas de dados relevantes e todas as páginas de índice onde a linha é inserida. Assim, quanto mais índices, mais demora a exclusão.
TRUNCATE
-> simplesmente remove todas as páginas de dados da tabela em massa, tornando esta uma opção mais eficiente para excluir o conteúdo de uma tabela.
Supondo que o acima esteja correto (por favor, corrija-me se não):
- Como diferentes modos de recuperação afetam cada instrução? Se houver algum efeito
- Ao excluir, todos os índices são verificados ou apenas aqueles onde a linha está? Eu diria que todos os índices são verificados (e não procurados?)
- Como os comandos são replicados? O comando SQL é enviado e processado em cada assinante? Ou o MSSQL é um pouco mais inteligente do que isso?
Isso está relacionado à contagem do número de registros que correspondem a uma determinada condição, por exemplo, invoice amount > $100
.
eu costumo preferir
COUNT(CASE WHEN invoice_amount > 100 THEN 1 END)
No entanto, isso é tão válido
SUM(CASE WHEN invoice_amount > 100 THEN 1 ELSE 0 END)
Eu teria pensado que COUNT é preferível por 2 razões:
- Transmite a intenção, que é
COUNT
COUNT
provavelmente envolve umai += 1
operação simples em algum lugar, enquanto SUM não pode contar com sua expressão como um valor inteiro simples.
Alguém tem fatos específicos sobre a diferença em RDBMS específicos?
Para uma consulta moderadamente complexa que estou tentando otimizar, notei que a remoção da TOP n
cláusula altera o plano de execução. Eu teria imaginado que, quando uma consulta inclui TOP n
o mecanismo de banco de dados, executaria a consulta ignorando a TOP
cláusula e, no final, apenas reduziria o resultado definido para o número n de linhas solicitadas. O plano de execução gráfico parece indicar que este é o caso -- TOP
é a "última" etapa. Mas parece que há mais coisas acontecendo.
Minha pergunta é: como (e por que) uma cláusula TOP n afeta o plano de execução de uma consulta?
Aqui está uma versão simplificada do que está acontecendo no meu caso:
A consulta está correspondendo linhas de duas tabelas, A e B.
Sem a TOP
cláusula, o otimizador estima que haverá 19.000 linhas da tabela A e 46.000 linhas da tabela B. O número real de linhas retornadas é 16.000 para A e 13.000 para B. Uma correspondência de hash é usada para unir esses dois conjuntos de resultados para um total de 69 linhas (então uma classificação é aplicada). Esta consulta acontece muito rapidamente.
Quando adiciono TOP 1001
o otimizador não usa uma correspondência de hash; em vez disso, ele primeiro classifica os resultados da tabela A (mesma estimativa/real de 19k/16k) e faz um loop aninhado na tabela B. O número estimado de linhas para a tabela B agora é 1, e o estranho é que TOP n
afeta diretamente o número estimado de execuções (busca de índice) contra B - parece ser sempre 2n+1 ou, no meu caso, 2003. Essa estimativa muda de acordo se eu mudar TOP n
. Obviamente, como essa é uma junção aninhada, o número real de execuções é 16k (o número de linhas da tabela A) e isso torna a consulta mais lenta.
A consulta tem uma ORDER BY
cláusula. Adicionar TOP
alterações onde no plano esse tipo ocorre, mas estou mais preocupado em como isso afeta o número de execuções de buscas de índice em relação à tabela B.
O cenário real é um pouco mais complexo, mas captura a ideia/comportamento básico. Ambas as tabelas são pesquisadas usando buscas de índice. Esta é a edição SQL Server 2008 R2 Enterprise.
Eu sou novo aqui, então seja gentil comigo. Tenho o seguinte cenário:
Eu tenho muitas tabelas que, por uma questão de simplicidade, são representadas em uma View no meu banco de dados MySQL. Meu problema é que preciso de um valor nessa view representando se é um tipo de evento ou outro (um booleano simples), que tentei alcançar com:
`gu`.`StoppingUnitEventME` = `ese`.`MonitoringElement` AS `IsStopingEvent`
O resultado é representado como int e, portanto, é lido pelo Entity Framework. O problema é que eu realmente preciso de um valor de retorno booleano, que tentei alcançar com:
CAST((`gu`.`StoppingUnitEventME` = `ese`.`MonitoringElement`) as boolean) AS `IsStopingEvent`
Isso resultou em um erro, que não é exibido para mim no MySQL Workbench (só recebo aquele irritante "Você tem um erro em ...").
Vocês podem por favor me ajudar?
Tentei resolver isso na minha aplicação, mas eu realmente prefiro isso resolvido no banco de dados, pois ele será usado por outros softwares posteriormente.