30 setembro 2016

Migrando Legados para MySQL 5.7 com Query Rewrite Plugin - Parte 1

Uma funcionalidade que pode fazer a diferença e viabilizar projetos de migração de legado para MySQL é a Query Rewrite Plugin. Com ela é possível interceptar comandos que são enviados ao MySQL e modificá-los online, sem a necessidade de alterar a aplicação.
Neste post, vamos entender como utilizar este recurso, com um exemplo real usando Moodle 2.3 no MySQL 5.7.

O que é o Query Rewrite Plugin

A partir do MySQL 5.7.6 há suporte para os Rewrite Plugins, que podem examinar e seletivamente reescrever comandos recebidos pelo servidor antes que sejam executados.
Quando uma instrução é recebido pelo MySQL Server, por exemplo um SELECT * FROM tabela where id = 1, ele passa por um parser que vai validar sintaxe e semântica, entre outros passos. Depois disso, o Otimizador de Consultas entra em ação, gerando e selecionando o melhor plano de execução para a query. Finalmente, o melhor plano é executado e o resultado retornado para o cliente que enviou a instrução.
Execução de Query no MySQL
Plugins Query Rewrite podem ser de dois subtipos:
- preparse: interceptam instruções antes do parser.
- postparse: agem logo depois do parser realizar seu trabalho.

Query Rewrite Plugins disponíveis

No pacote do MySQL Server 5.7 há dois Query Rewrite Plugins já disponíveis:
- rewrite_example: um exemplo de como funciona e como pode ser implementado um preparse Query Rewrite Plugin
- rewriter: um postparse plugin de uso mais genérico, para reescrever queries com SELECT, como veremos a seguir.

Como usar o plugin Rewriter (postparse)

A maneira mais fácil de enteder o funcionamento do Rewriter plugin é testando-o.
Passo 1 - Instale e configure o Rewriter plugin com:
cd /usr/share/mysql
mysql -uroot -p <install_rewriter.sql
Passo 2 - Como um teste simples, crie uma regra para transformar automaticamente SELECT ? em SELECT ? + 1:
mysql> INSERT INTO query_rewrite.rewrite_rules ( pattern, replacement ) VALUES ('SELECT ?', 'SELECT ? + 1');
Query OK, 1 row affected (0.06 sec)

mysql> SELECT * FROM query_rewrite.rewrite_rules\G
*************************** 1. row ***************************
                id: 1
           pattern: SELECT ?
  pattern_database: NULL
       replacement: SELECT ? + 1
           enabled: YES
           message: NULL
    pattern_digest: NULL
normalized_pattern: NULL
1 row in set (0.00 sec)
Passo 3 - Carregue a regra recém criada na memória:
mysql> CALL query_rewrite.flush_rewrite_rules();
Query OK, 0 rows affected (0.06 sec)
Passo 4 - Execute um SELECT:
mysql> SELECT 1;
+-------+
| 1 + 1 |
+-------+
|     2 |
+-------+
1 row in set, 1 warning (0.01 sec)

mysql> SHOW WARNINGS \G
*************************** 1. row ***************************
  Level: Note
   Code: 1105
Message: Query 'SELECT 1' rewritten to 'SELECT 1 + 1' by a query rewrite plugin
1 row in set (0.00 sec)
Você pode desabilitar apenas regras específicas com:
mysql> UPDATE query_rewrite.rewrite_rules SET enabled = 'NO' WHERE id = 1;
Veja que o Rewriter tem a capacidade de reescrever SELECTs. Ele examina instruções SELECT e pode reescrevê-los, com base nas regras de reescrita definidas na tabela query_rewrite.rewrite_rules. Os DBAs usam o plugin manipulando as regras armazenadas nesta tabela. Para efetivar novas regras (alterações na tabela rewrite_rules), o DBA deve chamar a procedure flush_rewrite_rules(), que carrega as regras na memória. Se houver algum erro durante a operação, o plugin o informará através da coluna message.
O plugin adiciona algumas variáveis ​de sistema para configuração:
SHOW GLOBAL VARIABLES LIKE 'rewriter%';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| rewriter_enabled | ON    |
| rewriter_verbose | 1     |
+------------------+-------+
Também são adicionadas variáveis de status com informações sobre sua operação:
SHOW GLOBAL STATUS LIKE 'rewriter%';
+-----------------------------------+-------+
| Variable_name                     | Value |
+-----------------------------------+-------+
| Rewriter_number_loaded_rules      | 1     |
| Rewriter_number_reloads           | 1     |
| Rewriter_number_rewritten_queries | 1     |
| Rewriter_reload_error             | OFF   |
+-----------------------------------+-------+
O Rewriter plugin atuará em instruções SELECT e em Prepared Statements, mas não fará reescritas para SELECTs dentro de Stored Programs ou UDFs.

Testando outro Query Rewrite Plugin (preparse)

O Rewriter é um QR plugin postparse. Isto significa que vai atuar depois do trabalho do parser. Vejamos agora como funciona um QR plugin preparse, que vai modificar a query antes de passar pelo parser:
mysql> INSTALL PLUGIN rewrite_example SONAME 'rewrite_example.so';
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT @@DEFAULT_STORAGE_ENGINE;
+--------------------------+
| @@default_storage_engine |
+--------------------------+
| InnoDB                   |
+--------------------------+
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS \G
*************************** 1. row ***************************
  Level: Note
   Code: 1105
Message: Query 'SELECT @@DEFAULT_STORAGE_ENGINE' rewritten to 'select @@default_storage_engine' by a query rewrite plugin
*************************** 2. row ***************************
  Level: Note
   Code: 1105
Message: Query 'SHOW WARNINGS' rewritten to 'show warnings' by a query rewrite plugin
2 rows in set, 1 warning (0.00 sec)
Note que a query foi reescrita pelo plugin para letras minúsculas. Este segundo plugin é apenas um exemplo, talvez sem muita aplicação prática. Porém, talvez você necessite realmente criar um preparse QR plugin em algumas situações, como no estudo de caso que veremos na parte 2.

Conclusão

Query Rewrite Plugins podem ter vários usos e são aliados poderosos quando não é possível alterar o código da aplicação. O Rewriter é uma implementação mais genérica, que pode ajudar se for necessário interceptar e reescrever SELECTs.

Referências

Nenhum comentário: