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 / dba / Perguntas / 327966
Accepted
lifeisajourney
lifeisajourney
Asked: 2023-06-07 03:30:25 +0800 CST2023-06-07 03:30:25 +0800 CST 2023-06-07 03:30:25 +0800 CST

A tabela temporária com menos número de linhas resulta em busca de índice clusterizado, enquanto mais linhas resultam em verificação de índice clusterizado - SQL Server

  • 772

Tenho a seguinte tabela e dados:

CREATE TABLE myTable (
    ID INT IDENTITY(1,1) PRIMARY KEY,
    Column1 VARCHAR(50),
    Column2 VARCHAR(50),
    Column3 VARCHAR(50),
    Column4 VARCHAR(50),
    Column5 VARCHAR(50),
    Column6 VARCHAR(50),
    Column7 VARCHAR(50),
    Column8 VARCHAR(50),
    Column9 VARCHAR(50),
    Column10 VARCHAR(50)
)

DECLARE @i INT = 1
DECLARE @j INT = 1
DECLARE @distinct_value_count INT = 20
DECLARE @distinct_value_count_with_more_rows INT = 3
DECLARE @rows_per_distinct_value INT = (20000 - (@distinct_value_count_with_more_rows * 2000)) / (@distinct_value_count - @distinct_value_count_with_more_rows)

WHILE @i <= @distinct_value_count
BEGIN
    DECLARE @current_rows_per_value INT = @rows_per_distinct_value
    IF @i <= @distinct_value_count_with_more_rows
    BEGIN
        SET @current_rows_per_value = @rows_per_distinct_value + 2000
    END
    
    SET @j = 1
    WHILE @j <= @current_rows_per_value
    BEGIN
        INSERT INTO myTable (Column1, Column2, Column3, Column4, Column5, Column6, Column7, Column8, Column9, Column10)
        VALUES ('Value' + CAST(@i AS VARCHAR(2)),
                'Value' + CAST(@j AS VARCHAR(5)),
                'Value' + CAST(@j + 1 AS VARCHAR(5)),
                'Value' + CAST(@j + 2 AS VARCHAR(5)),
                'Value' + CAST(@j + 3 AS VARCHAR(5)),
                'Value' + CAST(@j + 4 AS VARCHAR(5)),
                'Value' + CAST(@j + 5 AS VARCHAR(5)),
                'Value' + CAST(@j + 6 AS VARCHAR(5)),
                'Value' + CAST(@j + 7 AS VARCHAR(5)),
                'Value' + CAST(@j + 8 AS VARCHAR(5)))
        SET @j = @j + 1
    END
    
    SET @i = @i + 1
END

Alter Table dbo.myTable
Add Column11 varchar(50), Column12 varchar(50)

Alter Table dbo.myTable
Add dateModified datetime

Update dbo.myTable
  set Column11 = Column1
     ,Column12 = Column1

Update Top (10) dbo.myTable
   Set Column11 = 'Value7'
  Where Column1 = 'Value1'

Update Top (10) dbo.myTable
   Set Column12 = 'Value7'
  Where Column1 = 'Value1'

Update Top (10) dbo.myTable
   Set Column11 = 'Value6'
  Where Column1 = 'Value1'

Update Top (10) dbo.myTable
   Set Column12 = 'Value6'
  Where Column1 = 'Value1'

Update Top (10) dbo.myTable
   Set Column11 = 'Value5'
  Where Column1 = 'Value1'

Update Top (10) dbo.myTable
   Set Column12 = 'Value5'
  Where Column1 = 'Value1'

Update dbo.myTable
  set dateModified = getdate() + ID

CREATE NONCLUSTERED INDEX [Idx_col] ON [dbo].[myTable]
(
    [Column1] ASC,
    [Column11] ASC,
    [Column12] ASC,
    [dateModified] ASC
)
INCLUDE([Column5],[Column6]) 

Tenho que filtrar com base em algumas colunas e retornar todas as colunas da tabela. Para fazer isso, tenho um índice que cobre as colunas que precisam ser filtradas. Estou dividindo a consulta em duas partes:

  1. Obtenha todas as linhas de chave primária que satisfaçam o filtro e armazene-as em uma tabela temporária. Essa consulta usa o índice não clusterizado.

  2. Junte esta tabela temporária de volta à tabela principal na coluna de chave primária para que o índice clusterizado seja usado para obter todas as colunas.

No entanto, estou enfrentando um problema quando tento fazer isso. No primeiro cenário, estou obtendo todas as linhas filtradas em uma tabela temporária e, quando a incluo de volta na tabela principal, está fazendo uma varredura de índice clusterizado. No segundo cenário, estou obtendo apenas as 50 primeiras linhas na tabela temporária e, quando as incluo na tabela principal, está fazendo uma busca de índice clusterizado. Estou confuso sobre por que isso está acontecendo. Em ambos os casos, não há índice na tabela temporária. Agradeço se alguém puder me ajudar a entender o que está acontecendo. Obrigado!

Cenário 1:

SELECT id
INTO #tmpId
FROM myTable
WHERE Column1= 'Value1'
AND Column11 In( 'Value1','Value5','Value6', 'Value7')
And Column12 In ('Value1','Value6')
And dateModified > dateAdd(day,-5, getdate())

SELECT *
FROM myTable m
JOIN #tmpId t
ON m.id = t.id

drop table if exists #tmpId

Plano de Execução Cenário 1: https://www.brentozar.com/pastetheplan/?id=rkDAD-aLh

Cenário 2:

SELECT id
INTO #tmpId
FROM myTable
WHERE Column1= 'Value1'
AND Column11 In( 'Value1','Value5','Value6', 'Value7')
And Column12 In ('Value1','Value6')
And dateModified > dateAdd(day,-5, getdate())
Order by dateModified desc offset 0 rows fetch next 50 rows only

SELECT *
FROM myTable m
JOIN #tmpId t
ON m.id = t.id

drop table if exists #tmpId

Plano de Execução do Cenário 2: https://www.brentozar.com/pastetheplan/?id=rJVbuWaLh

sql-server
  • 2 2 respostas
  • 54 Views

2 respostas

  • Voted
  1. J.D.
    2023-06-07T20:34:31+08:002023-06-07T20:34:31+08:00

    Como Andy mencionou, não há nada de errado com os planos de execução que você forneceu. O SQL Engine está fazendo seu trabalho conforme o esperado. Diferentes operações são mais eficientes e rápidas, dependendo do tamanho dos dados que estão sendo processados. Index Seeks são proficientes para procurar quantidades menores de dados, enquanto Index Scans são geralmente mais proficientes para grandes quantidades de dados.

    Pense em um índice como uma lista telefônica. Os nomes são os dados e são classificados por, LastNameem seguida, por FirstName. Se você precisar procurar o número de telefone de uma única pessoa - John Smithpor exemplo, a maneira mais rápida seria pular diretamente para a página com S... LastNamese pular diretamente para onde Johnestá nessa página. Portanto, o equivalente a uma operação Index Seek.

    Agora, para um cenário diferente, digamos que você precise procurar o número de telefone de cada pessoa. Você pode pular arbitrariamente para a página 'S...' e depois pular para John, depois pular para a Bpágina e pular para Mary, e então pular para a Gpágina e pular para Tome depois pular de volta para a Spágina e pular para Ralph. Todo esse salto, em grandes quantidades, tem sobrecarga. Como você sabe que precisa ler todos os números de telefone na lista telefônica de qualquer maneira, seria mais rápido (menos sobrecarga) apenas começar pelo primeiro nome na primeira página e ler sequencialmente a lista telefônica até chegar ao sobrenome na última página. Isso seria o equivalente a uma operação Index Scan.

    Isso é essencialmente o que suas duas consultas e seus planos de execução estão fazendo.

    O Mecanismo SQL tem algo chamado de ponto de inflexão que ele usa como um limite para decidir entre quando uma varredura de índice seria mais eficiente ou uma busca de índice, com base na cardinalidade dos dados que estão sendo pesquisados. Mas é um algoritmo complexo que não pode ser calculado definitivamente como um valor estático , então não se preocupe em tentar descobrir o que é. O SQL Engine geralmente sabe melhor de qualquer maneira.


    Ajudaria se eu adicionasse um índice clusterizado à tabela temporária?

    Não há nada para ajudar aqui, como mencionado anteriormente, o SQL Engine está funcionando corretamente para fornecer a você os planos mais eficientes que julgar necessários. Mas se a sua pergunta é mais se isso mudaria alguma coisa, a resposta é não, não é provável.

    As escolhas que ele faz, com o algoritmo Tipping Point, são baseadas no número de linhas que precisam ser procuradas. Esse número não mudará apenas porque você adicionou um índice clusterizado à sua tabela temporária.

    • 2
  2. Best Answer
    Andy DB Analyst
    2023-06-07T04:44:15+08:002023-06-07T04:44:15+08:00

    A busca de índice é benéfica para recuperar uma quantidade relativamente pequena de dados. E pode desacelerar drasticamente uma consulta que recupera um grande número de linhas. Às vezes, o uso inapropriado de busca de índice pode retardar uma consulta por horas. É por isso que as informações sobre o número de linhas a serem selecionadas são cruciais para a otimização da consulta.

    Quando você seleciona 50 linhas, o índice de busca funciona perfeitamente. Mas parece que seus dados de 5 dias são muito grandes para que a busca de índice seja mais rápida do que a varredura de índice. É por isso que o otimizador usa a varredura de índice desta vez.

    Você também pode tentar usar as dicas do otimizador FORCESEEK e FORCESCAN para monitorar a diferença.

    • 0

relate perguntas

  • SQL Server - Como as páginas de dados são armazenadas ao usar um índice clusterizado

  • Preciso de índices separados para cada tipo de consulta ou um índice de várias colunas funcionará?

  • Quando devo usar uma restrição exclusiva em vez de um índice exclusivo?

  • Quais são as principais causas de deadlocks e podem ser evitadas?

  • Como determinar se um Índice é necessário ou necessário

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