Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Desempenho do MySQL de VIEW para tabelas combinado com UNION ALL


Concordo com todos os pontos da excelente resposta de Bill Karwin.

P: É uma prática normal criar uma visão para consulta de união discutida e usá-la em minhas junções, subseleções etc?

R: Com o MySQL, a prática mais normal é evitar o uso da instrução "CREATE VIEW".

P: Em termos de desempenho - será pior, igual ou melhor em comparação com apenas inseri-lo em junções, subseleções etc?

R: Fazer referência a um objeto de exibição terá o desempenho idêntico a uma exibição em linha equivalente.

(Pode haver um pouquinho mais de trabalho para pesquisar o objeto de exibição, verificar privilégios e, em seguida, substituir a referência de exibição pelo SQL armazenado, em vez de enviar uma instrução que é apenas um pouquinho mais longa. Mas qualquer um desses diferenças são insignificantes.)

P: Existem desvantagens de ter uma visão neste caso?

R: A maior desvantagem está em como o MySQL processa uma visualização, seja ela armazenada ou inline. O MySQL sempre executará a consulta de visualização e materializará os resultados dessa consulta como uma tabela MyISAM temporária. Mas não há diferença se a definição de exibição é armazenada ou se está incluída em linha. (Outros RDBMSs processam visualizações muito diferentes do MySQL).

Uma grande desvantagem de uma visualização é que os predicados da consulta externa NUNCA são empurrados para a consulta de visualização. Toda vez que você faz referência a essa visualização, mesmo com uma consulta para um único valor de id, o MySQL executará a consulta de visualização e criará uma tabela MyISAM temporária (sem índices nela), e ENTÃO o MySQL executará a consulta externa contra essa tabela temporária tabela MyISAM.

Então, em termos de desempenho, pense em uma referência a uma visão a par com "CREATE TEMPORARY TABLE t (cols) ENGINE=MyISAM " e "INSERT INTO t (cols) SELECT ... ".

MySQL na verdade se refere a uma visualização inline como uma "tabela derivada", e esse nome faz muito sentido, quando entendemos o que o MySQL está fazendo com ela.

Minha preferência pessoal é não usar a instrução "CREATE VIEW". A maior desvantagem (como eu vejo) é que ele "esconde" o SQL que está sendo executado. Para o futuro leitor, a referência à view se parece com uma tabela. E então, quando ele for escrever uma instrução SQL, ele fará referência à visão como se fosse uma tabela, muito conveniente. Então ele decide que vai juntar aquela mesa a ela mesma, com outra referência a ela. (Para a segunda referência, o MySQL também executa essa consulta novamente e cria outra tabela MyISAM temporária (e não indexada). E agora há uma operação JOIN nela. E então um predicado "WHERE view.column ='foo'" é adicionado na consulta externa.

Acaba "escondendo" a melhoria de desempenho mais óbvia, deslizando esse predicado para a consulta de visualização.

E então, alguém chega e decide que vai criar uma nova visão, que faz referência à visão antiga. Ele só precisa de um subconjunto de linhas e não pode modificar a visão existente porque isso pode quebrar alguma coisa, então ele cria uma nova visão... CREATE VIEW myview FROM publicview p WHERE p.col ='foo'.

E, agora, uma referência a myview vai primeiro executar a consulta publicview, criar uma tabela MyISAM temporária, então a consulta myview será executada contra isso, criando outra tabela MyISAM temporária, na qual a consulta externa será executada.

Basicamente, a conveniência da visualização tem o potencial de problemas de desempenho não intencionais. Com a definição de visualização disponível no banco de dados para qualquer pessoa usar, alguém a usará, mesmo quando não for a solução mais apropriada.

Pelo menos com uma visualização em linha, a pessoa que escreve a instrução SQL está mais ciente do SQL real que está sendo executado, e ter todo esse SQL definido oferece a oportunidade de ajustá-lo para desempenho.

Meus dois centavos.

DOMING BASTLY SQL

Acho que aplicar regras regulares de formatação (que minhas ferramentas fazem automaticamente) pode transformar o SQL monstruoso em algo que eu possa ler e trabalhar.
SELECT row.col1
     , row.col2
     , person.*
  FROM some_table row
  LEFT
  JOIN ( SELECT 'person'  AS `person_type`
              , p.id      AS `id`
              , CONCAT(p.first_name,' ',p.surname) AS `name`
           FROM person p
          UNION ALL
         SELECT 'company' AS `person_type`
              , c.id      AS `id`
              , c.name    AS `name`
           FROM company c
       ) person
    ON person.id = row.person_id
   AND person.person_type = row.person_type

Eu teria a mesma probabilidade de evitar a exibição em linha e usar expressões condicionais na lista SELECT, embora isso fique mais complicado para muitas colunas.
SELECT row.col1
     , row.col2
     , row.person_type AS ref_person_type
     , row.person_id   AS ref_person_id
     , CASE
       WHEN row.person_type = 'person'  THEN p.id 
       WHEN row.person_type = 'company' THEN c.id
       END AS `person_id`
     , CASE
       WHEN row.person_type = 'person'  THEN CONCAT(p.first_name,' ',p.surname)
       WHEN row.person_type = 'company' THEN c.name
       END AS `name`
  FROM some_table row
  LEFT
  JOIN person p
    ON row.person_type = 'person'
   AND p.id = row.person_id
  LEFT
  JOIN company c
    ON row.person_type = 'company'
   AND c.id = row.person_id