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 / 302443
Accepted
Charlieface
Charlieface
Asked: 2021-11-11 15:21:48 +0800 CST2021-11-11 15:21:48 +0800 CST 2021-11-11 15:21:48 +0800 CST

Manutenção de exibição indexada com chave estrangeira não elidida ao inserir a linha pai

  • 772

TL;DR;

Dada uma exibição indexada que tem JOINentre duas tabelas que já possuem um relacionamento de chave estrangeira junto com um WHEREpredicado na tabela pai.
Ao inserir na tabela pai da chave estrangeira, o compilador está adicionando manutenção de índice ao plano, mesmo que seja provável que não existam linhas correspondentes.

Isso é um bug ou talvez uma otimização perdida? Ou existe alguma falácia lógica ou algébrica em que estou?

Configurar

CREATE TABLE Parent (Id int identity primary key, SomeCol bit not null, OtherCol int not null);

CREATE TABLE Child (Id int identity primary key, ParentId int not null references Parent (Id) INDEX IX_Parent NONCLUSTERED);
CREATE VIEW dbo.vChild
WITH SCHEMABINDING
AS
SELECT c.Id, c.ParentId
FROM dbo.Child c
JOIN dbo.Parent p ON p.Id = c.ParentId
-- WHERE p.SomeCol = 0;  -- problem dependent on this line
CREATE UNIQUE CLUSTERED INDEX CX_vChild ON vChild (Id)

db<>fiddle com WHERE
db<>fiddle sem WHERE

Neste estágio, qualquer UPDATEcoluna que afete na visão, e qualquer DELETE, das tabelas da visão acionam, com razão, a manutenção da visão. O compilador pegará as linhas modificadas, as colocará em spool e as alimentará através das junções da visão, enviando quaisquer resultados para o índice da visão.

O mesmo pode ser dito para inserções para Child, porque uma linha Parentjá pode existir para (que se qualifica em relação a WHERE) e, portanto, a nova Childlinha pode se qualificar para a junção.

Problema

Ao inserir em Parent, é provável que a manutenção do índice não precise ser feita. Uma linha correspondente ainda não pode existir Childdevido ao relacionamento de chave estrangeira, portanto, não pode haver linhas da inserção que se qualifiquem para a exibição.

Se você executar o script a seguir, verá que nenhuma manutenção de exibição é feita.

INSERT Parent (SomeCol, OtherCol)
VALUES (0, 100);

PasteThePlan

insira a descrição da imagem aqui

Muito claramente, o compilador pode deduzir que a manutenção da visão não é necessária aqui.

No entanto, se você descomentar a linha WHERE p.SomeCol = 0na definição de exibição, de repente você obterá manutenção de exibição. Portanto, a adição de outra coluna à exibição, que não é uma coluna de junção e não possui um relacionamento de chave estrangeira, causa isso. Isso ocorre apesar da mesma lógica relacional aplicada: a inserção provavelmente ainda não se qualifica para a exibição, devido à coluna de chave estrangeira que ainda está lá.

PasteThePlan

insira a descrição da imagem aqui

Curiosamente, o compilador ainda pode reconhecer alguns casos em que a inserção não se qualificará para a exibição (e apesar desse exemplo específico ser parametrizado automaticamente).

Aqui o compilador reconhece que SomeColfalha o WHERE, e não há necessidade de fazer manutenção de índice.

INSERT Parent (SomeCol, OtherCol)
VALUES (1, 100);

PasteThePlan

insira a descrição da imagem aqui

sql-server t-sql
  • 1 1 respostas
  • 140 Views

1 respostas

  • Voted
  1. Best Answer
    Paul White
    2021-11-17T06:42:02+08:002021-11-17T06:42:02+08:00

    O otimizador não faz o tipo de raciocínio que você descreve.

    Em vez disso, depende de um conjunto padrão de recursos frequentemente úteis, fáceis de implementar e rápidos de verificar, como detecção de contradição e remoção de junção redundante para produzir simplificações úteis.

    É a interação entre esses recursos modulares que pode produzir comportamentos aparentemente complexos que as pessoas às vezes confundem com otimização extensiva e análise semântica profunda.

    O comportamento observado pode ser explicado por referência a esses recursos padrão do otimizador e à maneira como as visualizações indexadas são mantidas usando a álgebra delta .


    Essa consulta toca apenas a tabela Filho no plano de execução porque a linha pai tem a garantia de existir:

    SELECT c.Id, c.ParentId
    FROM dbo.Child c
    JOIN dbo.Parent p ON p.Id = c.ParentId
    

    Quando você adiciona um predicado na tabela Pai, isso não é mais logicamente possível:

    SELECT c.Id, c.ParentId
    FROM dbo.Child c
    JOIN dbo.Parent p ON p.Id = c.ParentId
    WHERE p.SomeCol = 0;  -- problem dependent on this line
    

    O mesmo mecanismo subjacente é responsável por remover a junção na subárvore de manutenção produzida através da álgebra delta. Você pode ver um pouco disso com o sinalizador de rastreamento 8619, quando a saída de depuração inclui:

    Full Join removed for table TBL: dbo.Parent
    

    Para uma inserção, o delta produzido é muito semelhante às consultas ilustrativas acima. Para uma atualização, exclusão ou mesclagem, os deltas podem ser diferentes porque informações diferentes podem ser necessárias para manter a exibição. (No seu exemplo específico, é difícil ver o que pode ser atualizado na tabela Pai, mas a questão é principalmente sobre uma inserção.)


    Quando a WHEREcláusula está presente, um Filtro nesse predicado aparece na parte de manutenção do plano.

    Para esta instrução, é detectada uma contradição entre o filtro em SomeCol = 0 e o valor de SomeCol especificado na inserção. Essa contradição resulta em toda a subárvore de manutenção sendo garantida vazia e, portanto, removida:

    INSERT Parent (SomeCol, OtherCol)
    VALUES (1, 100);
    

    Para esta afirmação, não há contradição, mas o Filtro é redundante e, portanto, removido. A subárvore de manutenção não é garantida vazia e, portanto, não é removida:

    INSERT Parent (SomeCol, OtherCol)
    VALUES (0, 100);
    

    Se você usar, por exemplo, variáveis ​​ou parâmetros locais em vez de literais, o Filtro reaparecerá.

    O exemplo dado não é é simples parametrizado. Ele se qualificou para consideração, mas a parametrização não foi determinada como segura. Não se deixe enganar pela presença de marcadores como @1no texto. Consulte Por que um plano com otimização FULL mostra parametrização simples?

    • 3

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