SlideShare a Scribd company logo
Preparse Query Rewrite Plugins
New SQL syntax for fun & performance
Sveta Smirnova
Principal Support Engineer
January, 30, 2016
Table of Contents
•Introducing new SQL syntax
•Working with results
•Variables
•Summary
2 www.percona.com
Introducing new
SQL syntax
3 www.percona.com
MySQL often receives blames
• From mascots and from humans
4 www.percona.com
MySQL often receives blames
• From mascots and from humans
• It cannot make a toast
4 www.percona.com
MySQL often receives blames
• From mascots and from humans
• It cannot make a toast
• It does not support some syntax
4 www.percona.com
Or does it?
• FILTER clause in MySQL on my home
machine
5 www.percona.com
Or does it?
• FILTER clause in MySQL on my home
machine
5 www.percona.com
Or does it?
• FILTER clause in MySQL on my home
machine
• But not in the user manual
5 www.percona.com
How is it done?
• With 181 lines of code
• Including comments!
• And new Query Rewrite Plugin interface
6 www.percona.com
A little bit of history
• First introduced in version 5.7.5
• Was available at MySQL Labs
• Two types of plugins
• Pre-parse
• Post-parse
7 www.percona.com
Today
• Part of Audit plugin interface
• Step in at
• MYSQL AUDIT GENERAL ALL
• MYSQL AUDIT CONNECTION ALL
• MYSQL AUDIT PARSE ALL
• MYSQL AUDIT PARSE PREPARSE
• MYSQL AUDIT PARSE POSTPARSE
• MYSQL AUDIT AUTHORIZATION ALL
• ...
8 www.percona.com
Plugin skeleton
#include <mysql/plugin.h>
#include <mysql/plugin_audit.h> - Audit plugin declaration
...
static MYSQL_PLUGIN plugin_info_ptr; - Pointer to the plugin
...
static int filter_plugin_init(MYSQL_PLUGIN plugin_ref); - Plugin initialization
...
static int filter(MYSQL_THD thd, mysql_event_class_t event_class,
const void *event); - Entry point for MYSQL_AUDIT_PARSE_PREPARSE
...
static st_mysql_audit filter_plugin_descriptor;
...
mysql_declare_plugin(filter_plugin);
9 www.percona.com
Plugin descriptor
static st_mysql_audit filter_plugin_descriptor= {
MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */
NULL,
filter, /* implements FILTER */
// You can also use MYSQL_AUDIT_PARSE_ALL
{ 0, 0, (unsigned long) MYSQL_AUDIT_PARSE_PREPARSE,}
};
10 www.percona.com
Plugin declaration
mysql_declare_plugin(filter_plugin)
{
MYSQL_AUDIT_PLUGIN,
&filter_plugin_descriptor,
"filter_plugin",
"Sveta Smirnova",
"FILTER SQL:2003 support for MySQL",
PLUGIN_LICENSE_GPL,
filter_plugin_init,
NULL, /* filter_plugin_deinit - TODO */
0x0001, /* version 0.0.1 */
NULL, /* status variables */
NULL, /* system variables */
NULL, /* config options */
0, /* flags */
}
mysql_declare_plugin_end;
11 www.percona.com
Memory management for plugins
#include <my_thread.h> // my_thread_handle needed by mysql_memory.h
#include <mysql/psi/mysql_memory.h>
...
static PSI_memory_key key_memory_filter;
static PSI_memory_info all_rewrite_memory[]=
{
{ &key_memory_filter, "filter", 0 }
};
static int filter_plugin_init(MYSQL_PLUGIN plugin_ref)
{
plugin_info_ptr= plugin_ref;
const char* category= "sql";
int count;
count= array_elements(all_rewrite_memory);
mysql_memory_register(category, all_rewrite_memory, count);
return 0; /* success */
}
12 www.percona.com
SQL:2003
<filter clause> ::=
FILTER <left paren> WHERE <search condition> <right paren>
(10.9 <aggregate function>, 5WD-02-Foundation-2003-09.pdf, p.505)
Only for aggregate functions:
<computational operation> ::=
AVG | MAX | MIN | SUM | EVERY | ANY
| SOME | COUNT | STDDEV_POP | STDDEV_SAMP
| VAR_SAMP | VAR_POP | COLLECT | FUSION | INTERSECTION
<set quantifier> ::=
DISTINCT
| ALL
MySQL only supports
COUNT | AVG | SUM | MAX | MIN
| STDDEV_POP | STDDEV_SAMP
| VAR_SAMP | VAR_POP
13 www.percona.com
Implementing FILTER clause
• FILTER is practically
CASE WHEN foo THEN bar ELSE NULL
• So we only need to catch
FUNCTION(var) FILTER(WHERE foo)
• And replace it with CASE
14 www.percona.com
Catching up the query
static int filter(MYSQL_THD thd, // MySQL Thread object
mysql_event_class_t event_class, // Class of the event
const void *event // Event itself
)
{
const struct mysql_event_parse *event_parse=
static_cast<const struct mysql_event_parse *>(event);
if (event_parse->event_subclass != MYSQL_AUDIT_PARSE_PREPARSE)
return 0;
string subject= event_parse->query.str; // Original query
string rewritten_query;
//requires std::regex and GCC 4.9+
regex filter_clause_star("(COUNT)((s**s*))s+"
+ "FILTERs*(s*WHEREs+([^)]+)s*)",
ECMAScript | icase);
rewritten_query= regex_replace(subject, filter_clause_star,
"$1(CASE WHEN $3 THEN 1 ELSE NULL END)");
...
15 www.percona.com
Rewritten query
void _rewrite_query(const void *event,
const struct mysql_event_parse *event_parse,
char const* new_query
)
{
char *rewritten_query= static_cast<char *>(my_malloc(
key_memory_filter, strlen(new_query) + 1, MYF(0)));
strncpy(rewritten_query, new_query, strlen(new_query));
rewritten_query[strlen(new_query)]= ’0’;
event_parse->rewritten_query->str= rewritten_query; // Rewritten query
event_parse->rewritten_query->length=strlen(new_query);
// You must set this flag to inform MySQL Server what query was rewritten
*((int *)event_parse->flags)|=
(int)MYSQL_AUDIT_PARSE_REWRITE_PLUGIN_QUERY_REWRITTEN;
}
16 www.percona.com
Working with
results
17 www.percona.com
Can we do better?
• Playing with syntax is fun
• But can we introduce something more
MySQL-ish?
18 www.percona.com
Custom hint plugin
• MySQL 5.7 has Optimizer Hints
SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1
FROM t3 WHERE f1 > 30 AND f1 < 33;
SELECT /*+ BKA(t1) NO_BKA(t2) */ * FROM t1 INNER JOIN t2 WHERE ...;
SELECT /*+ NO_ICP(t1, t2) */ * FROM t1 INNER JOIN t2 WHERE ...;
SELECT /*+ SEMIJOIN(FIRSTMATCH, LOOSESCAN) */ * FROM t1 ...;
EXPLAIN SELECT /*+ NO_ICP(t1) */ * FROM t1 WHERE ...;
19 www.percona.com
Custom hint plugin
• MySQL 5.7 has Optimizer Hints
• But sometimes thread-specific buffers
affect query execution
• Common workaround exists:
SET tmp_table_size=1073741824;
SELECT * FROM t1 INNER JOIN t2 WHERE ...;
SET tmp_table_size=DEFAULT;
• Workaround requires processing result set
of each of these statements
19 www.percona.com
Custom hint plugin
• MySQL 5.7 has Optimizer Hints
• But sometimes thread-specific buffers
affect query execution
• Workaround requires processing result set
of each of these statements
• This is why I extended optimizer hint
syntax
SELECT /*+ join_buffer_size=16384 */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33;
SELECT /*+ tmp_table_size=1073741824 BKA(t1) NO_BKA(t2) */ *
FROM t1 INNER JOIN t2 WHERE ...;
19 www.percona.com
New features
• For Custom Hints we need to:
• Store previous values of thread
variables we are going to modify
• Modify variables
• Revert them back before sending result
20 www.percona.com
Store previous values
// map to store modified variables
static map <my_thread_id, map<supported_hints_t, ulonglong> > modified_variables;
...
/* The job */
static int custom_hint(MYSQL_THD thd, mysql_event_class_t event_class,
const void *event)
{
...
// If we have a match store create map of thread variables
std::map<supported_hints_t, ulonglong> current;
...
After processing variables store them in modified_variables map
modified_variables[thd->thread_id()]= current;
...
21 www.percona.com
Modify variables
• Since we have access to MYSQL THD
this is easy:
switch(get_hint_switch(ssm[1]))
{
case JOIN_BUFFER_SIZE:
current[JOIN_BUFFER_SIZE]= thd->variables.join_buff_size;
thd->variables.join_buff_size= stoull(ssm[2]);
break;
case TMP_TABLE_SIZE:
current[TMP_TABLE_SIZE]= thd->variables.tmp_table_size;
thd->variables.tmp_table_size= stoull(ssm[2]);
break;
...
22 www.percona.com
Revert variables back
• First we need to tell plugin descriptor what
we need
MYSQL AUDIT GENERAL RESULT
static st_mysql_audit custom_hint_plugin_descriptor= {
MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */
NULL,
custom_hint, /* implements custom hints */
{ (unsigned long) MYSQL_AUDIT_GENERAL_RESULT, 0,
(unsigned long) MYSQL_AUDIT_PARSE_PREPARSE,
}
};
23 www.percona.com
Revert variables back
• First we need to tell plugin descriptor what
we need
MYSQL AUDIT GENERAL RESULT
• Then revert variables before sending result
if (event_general->event_subclass == MYSQL_AUDIT_GENERAL_RESULT)
{
map<my_thread_id, map<supported_hints_t, ulonglong> >::iterator
current= modified_variables.find(thd->thread_id());
if (current != modified_variables.end())
{
for (map<supported_hints_t, ulonglong>::iterator it=
current->second.begin(); it!= current->second.end(); ++it)
{
switch(it->first)
{
case JOIN_BUFFER_SIZE:
thd->variables.join_buff_size= it->second;
break;
23 www.percona.com
Revert variables back
• First we need to tell plugin descriptor what
we need
MYSQL AUDIT GENERAL RESULT
• Then revert variables before sending result
• And, finally, erase stored values for current
thread:
modified_variables.erase(current);
23 www.percona.com
Before Custom Hint Plugin
mysql> flush status;
Query OK, 0 rows affected (0.00 sec)
mysql> select count(*), sum(c) from
-> (select s, count(s) c from joinit where i < 1000000 group by s) t;
+----------+--------+
| count(*) | sum(c) |
+----------+--------+
| 737882 | 737882 |
+----------+--------+
1 row in set (24.70 sec)
mysql> show status like ’Created_tmp_disk_tables’;
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 2 | -- 2 temporary tables on disk
+-------------------------+-------+
1 row in set (0.00 sec)
24 www.percona.com
Custom Hint Plugin at work
mysql> flush status;
Query OK, 0 rows affected (0.00 sec)
mysql> select /*+ tmp_table_size=134217728 max_heap_table_size=134217728 */
-> count(*), sum(c) from
-> (select s, count(s) c from joinit where i < 1000000 group by s) t;
+----------+--------+
| count(*) | sum(c) |
+----------+--------+
| 737882 | 737882 |
+----------+--------+
1 row in set, 2 warnings (6.21 sec) -- 4 times speed gain!
mysql> show status like ’Created_tmp_disk_tables’;
+-------------------------+-------+
| Variable_name | Value |
+-------------------------+-------+
| Created_tmp_disk_tables | 0 | -- No disk-based temporary table!
+-------------------------+-------+
1 row in set (0.00 sec)
25 www.percona.com
Variables
26 www.percona.com
BACKUP DATABASE plugin
• Very simple syntax
• mysql> BACKUP SERVER;
+---------------------------------+
| Backup finished with status OK! |
+---------------------------------+
| Backup finished with status OK! |
+---------------------------------+
1 row in set, 1 warning (42.92 sec)
27 www.percona.com
BACKUP DATABASE plugin
• Very simple syntax
• Supports many tools
• mysqldump
• mysqlpump
• mysqlbackup
• XtraBackup - Planned!
27 www.percona.com
BACKUP DATABASE plugin
• Very simple syntax
• Supports many tools
• Needs to pass options
• Credentials
• Backup directory
• Custom
27 www.percona.com
Customization: credentials
• We have access to
• MYSQL_THR->security_context
• thd->security_context()->user().str
• Password still has to be in the configuration file, under
[client]
or
[toolname]
section
• System variables
• Since we are interested in backing up local server we will use
mysqld_unix_port
28 www.percona.com
Customization: variables
• Global variables - Example only!
static MYSQL_SYSVAR_STR(backup_dir, backup_dir_value, PLUGIN_VAR_MEMALLOC,
"Default directory...", NULL, NULL, NULL);
static MYSQL_SYSVAR_ENUM(backup_tool, backup_tool_name,
PLUGIN_VAR_RQCMDARG, "Backup tool. Possible values:
mysqldump|mysqlbackup", NULL, NULL,
MYSQLDUMP, &supported_tools_typelib);
• Thread variables
• Add to plugin declaration
29 www.percona.com
Customization: variables
• Global variables - Example only!
• Thread variables
static MYSQL_THDVAR_STR(backup_dir, PLUGIN_VAR_MEMALLOC,
"Default directory...", NULL, NULL, NULL);
static MYSQL_THDVAR_ENUM(backup_tool, PLUGIN_VAR_RQCMDARG,
"Backup tool. Possible values:
mysqldump|mysqlbackup|mysqlpump", NULL, NULL,
MYSQLDUMP, &supported_tools_typelib);
...
• Add to plugin declaration
29 www.percona.com
Customization: variables
• Global variables - Example only!
• Thread variables
• Add to plugin declaration
static struct st_mysql_sys_var *mysqlbackup_plugin_sys_vars[] = {
MYSQL_SYSVAR(backup_dir),
MYSQL_SYSVAR(backup_tool),
MYSQL_SYSVAR(backup_tool_basedir),
MYSQL_SYSVAR(backup_tool_options),
NULL
};
mysql_declare_plugin(mysqlbackup_plugin)
{
MYSQL_AUDIT_PLUGIN,
&mysqlbackup_plugin_descriptor,
"mysqlbackup_plugin",
...
NULL, /* status variables */
mysqlbackup_plugin_sys_vars, /* system variables */
...
29 www.percona.com
Summary
30 www.percona.com
More possibilities
• Custom locks
• Access to thread- and server-specific
variables
• Fine control at multiple steps of query
execution
• More
31 www.percona.com
Code
• https://github.com/svetasmirnova/
• filter plugin
• custom hint plugin
• mysqlbackup plugin
32 www.percona.com
More information
• MySQL source dir/plugin
• rewriter
• rewrite example
• Writing Audit Plugins manual
• MySQL Services for Plugins manual
33 www.percona.com
Place for your questions
???
34 www.percona.com
Thank you!
http://www.slideshare.net/SvetaSmirnova
https://twitter.com/svetsmirnova
35 www.percona.com

More Related Content

What's hot (20)

PDF
Performance Schema for MySQL Troubleshooting
Sveta Smirnova
 
PDF
MySQL Query tuning 101
Sveta Smirnova
 
PDF
Preparse Query Rewrite Plugins
Sveta Smirnova
 
PDF
MySQL Performance Schema in Action
Sveta Smirnova
 
PDF
Character Encoding - MySQL DevRoom - FOSDEM 2015
mushupl
 
PDF
Basic MySQL Troubleshooting for Oracle DBAs
Sveta Smirnova
 
PDF
UKOUG 2011: Practical MySQL Tuning
FromDual GmbH
 
PDF
New features in Performance Schema 5.7 in action
Sveta Smirnova
 
PDF
Performance Schema for MySQL troubleshooting
Sveta Smirnova
 
PDF
Introduction to MySQL Query Tuning for Dev[Op]s
Sveta Smirnova
 
PDF
Highload Perf Tuning
HighLoad2009
 
PDF
Performance Schema for MySQL Troubleshooting
Sveta Smirnova
 
PDF
Introduction into MySQL Query Tuning for Dev[Op]s
Sveta Smirnova
 
PDF
Introduction into MySQL Query Tuning
Sveta Smirnova
 
PDF
MySQL Troubleshooting with the Performance Schema
Sveta Smirnova
 
PDF
Noinject
Justin Swanhart
 
PDF
Summary tables with flexviews
Justin Swanhart
 
PDF
Flexviews materialized views for my sql
Justin Swanhart
 
PDF
MySQL/MariaDB query optimizer tuning tutorial from Percona Live 2013
Sergey Petrunya
 
PDF
Fosdem2012 mariadb-5.3-query-optimizer-r2
Sergey Petrunya
 
Performance Schema for MySQL Troubleshooting
Sveta Smirnova
 
MySQL Query tuning 101
Sveta Smirnova
 
Preparse Query Rewrite Plugins
Sveta Smirnova
 
MySQL Performance Schema in Action
Sveta Smirnova
 
Character Encoding - MySQL DevRoom - FOSDEM 2015
mushupl
 
Basic MySQL Troubleshooting for Oracle DBAs
Sveta Smirnova
 
UKOUG 2011: Practical MySQL Tuning
FromDual GmbH
 
New features in Performance Schema 5.7 in action
Sveta Smirnova
 
Performance Schema for MySQL troubleshooting
Sveta Smirnova
 
Introduction to MySQL Query Tuning for Dev[Op]s
Sveta Smirnova
 
Highload Perf Tuning
HighLoad2009
 
Performance Schema for MySQL Troubleshooting
Sveta Smirnova
 
Introduction into MySQL Query Tuning for Dev[Op]s
Sveta Smirnova
 
Introduction into MySQL Query Tuning
Sveta Smirnova
 
MySQL Troubleshooting with the Performance Schema
Sveta Smirnova
 
Noinject
Justin Swanhart
 
Summary tables with flexviews
Justin Swanhart
 
Flexviews materialized views for my sql
Justin Swanhart
 
MySQL/MariaDB query optimizer tuning tutorial from Percona Live 2013
Sergey Petrunya
 
Fosdem2012 mariadb-5.3-query-optimizer-r2
Sergey Petrunya
 

Viewers also liked (7)

PDF
SQL? NoSQL? NewSQL?!? What's a Java developer to do? - PhillyETE 2012
Chris Richardson
 
PDF
Application development with Oracle NoSQL Database 3.0
Anuj Sahni
 
ODP
My sql Syntax
Reka
 
DOC
Complete Sql Server querries
Ibrahim Jutt
 
ODP
Prabu's sql quries
Prabu Cse
 
PPTX
MySql: Queries
DataminingTools Inc
 
DOCX
Ab initio is one of the popular etl tools that is in the market
eercreddy
 
SQL? NoSQL? NewSQL?!? What's a Java developer to do? - PhillyETE 2012
Chris Richardson
 
Application development with Oracle NoSQL Database 3.0
Anuj Sahni
 
My sql Syntax
Reka
 
Complete Sql Server querries
Ibrahim Jutt
 
Prabu's sql quries
Prabu Cse
 
MySql: Queries
DataminingTools Inc
 
Ab initio is one of the popular etl tools that is in the market
eercreddy
 
Ad

Similar to Introducing new SQL syntax and improving performance with preparse Query Rewrite Plugins (20)

PDF
Percona Live 2012PPT: MySQL Query optimization
mysqlops
 
PPTX
Mysql query optimization best practices and indexing
Alkin Tezuysal
 
PPTX
Alkin Tezuysal "MySQL Query Optimization Best Practices and Indexing"
Fwdays
 
PDF
Query Optimization with MySQL 5.6: Old and New Tricks
MYXPLAIN
 
PDF
Mysql tracing
Anis Berejeb
 
PDF
Mysql tracing
Anis Berejeb
 
PPTX
PHP FUNCTIONS
Zeeshan Ahmed
 
ODP
HTTP, JSON, JavaScript, Map&Reduce built-in to MySQL
Ulf Wendel
 
PDF
My sql 5.7-upcoming-changes-v2
Morgan Tocker
 
PDF
Query Optimization with MySQL 5.6: Old and New Tricks - Percona Live London 2013
Jaime Crespo
 
PPT
MySQL Performance Tuning at COSCUP 2014
Ryusuke Kajiyama
 
PPTX
Работа с индексами - лучшие практики для MySQL 5.6, Петр Зайцев (Percona)
Ontico
 
PDF
Mysql 51 Plugin Development Sergei Golubchik Andrew Hutchings
kilonboache
 
PDF
Mysql 51 Plugin Development Sergei Golubchik Andrew Hutchings
aistdah4598
 
PPTX
20141011 mastering mysqlnd
do_aki
 
PDF
56 Query Optimization
MYXPLAIN
 
ODP
Beyond php - it's not (just) about the code
Wim Godden
 
PDF
Percona toolkit
Karwin Software Solutions LLC
 
PPTX
Php and database functionality
Sayed Ahmed
 
PPTX
Php and database functionality
Sayed Ahmed
 
Percona Live 2012PPT: MySQL Query optimization
mysqlops
 
Mysql query optimization best practices and indexing
Alkin Tezuysal
 
Alkin Tezuysal "MySQL Query Optimization Best Practices and Indexing"
Fwdays
 
Query Optimization with MySQL 5.6: Old and New Tricks
MYXPLAIN
 
Mysql tracing
Anis Berejeb
 
Mysql tracing
Anis Berejeb
 
PHP FUNCTIONS
Zeeshan Ahmed
 
HTTP, JSON, JavaScript, Map&Reduce built-in to MySQL
Ulf Wendel
 
My sql 5.7-upcoming-changes-v2
Morgan Tocker
 
Query Optimization with MySQL 5.6: Old and New Tricks - Percona Live London 2013
Jaime Crespo
 
MySQL Performance Tuning at COSCUP 2014
Ryusuke Kajiyama
 
Работа с индексами - лучшие практики для MySQL 5.6, Петр Зайцев (Percona)
Ontico
 
Mysql 51 Plugin Development Sergei Golubchik Andrew Hutchings
kilonboache
 
Mysql 51 Plugin Development Sergei Golubchik Andrew Hutchings
aistdah4598
 
20141011 mastering mysqlnd
do_aki
 
56 Query Optimization
MYXPLAIN
 
Beyond php - it's not (just) about the code
Wim Godden
 
Php and database functionality
Sayed Ahmed
 
Php and database functionality
Sayed Ahmed
 
Ad

More from Sveta Smirnova (20)

PDF
War Story: Removing Offensive Language from Percona Toolkit
Sveta Smirnova
 
PDF
MySQL 2024: Зачем переходить на MySQL 8, если в 5.х всё устраивает?
Sveta Smirnova
 
PDF
Database in Kubernetes: Diagnostics and Monitoring
Sveta Smirnova
 
PDF
MySQL Database Monitoring: Must, Good and Nice to Have
Sveta Smirnova
 
PDF
MySQL Cookbook: Recipes for Developers
Sveta Smirnova
 
PDF
MySQL Performance for DevOps
Sveta Smirnova
 
PDF
MySQL Test Framework для поддержки клиентов и верификации багов
Sveta Smirnova
 
PDF
MySQL Cookbook: Recipes for Your Business
Sveta Smirnova
 
PDF
Производительность MySQL для DevOps
Sveta Smirnova
 
PDF
MySQL Performance for DevOps
Sveta Smirnova
 
PDF
How to Avoid Pitfalls in Schema Upgrade with Percona XtraDB Cluster
Sveta Smirnova
 
PDF
How to migrate from MySQL to MariaDB without tears
Sveta Smirnova
 
PDF
Modern solutions for modern database load: improvements in the latest MariaDB...
Sveta Smirnova
 
PDF
How Safe is Asynchronous Master-Master Setup?
Sveta Smirnova
 
PDF
Современному хайлоду - современные решения: MySQL 8.0 и улучшения Percona
Sveta Smirnova
 
PDF
How to Avoid Pitfalls in Schema Upgrade with Galera
Sveta Smirnova
 
PDF
How Safe is Asynchronous Master-Master Setup?
Sveta Smirnova
 
PDF
Billion Goods in Few Categories: How Histograms Save a Life?
Sveta Smirnova
 
PDF
A Billion Goods in a Few Categories: When Optimizer Histograms Help and When ...
Sveta Smirnova
 
PDF
Что нужно знать о трёх топовых фичах MySQL
Sveta Smirnova
 
War Story: Removing Offensive Language from Percona Toolkit
Sveta Smirnova
 
MySQL 2024: Зачем переходить на MySQL 8, если в 5.х всё устраивает?
Sveta Smirnova
 
Database in Kubernetes: Diagnostics and Monitoring
Sveta Smirnova
 
MySQL Database Monitoring: Must, Good and Nice to Have
Sveta Smirnova
 
MySQL Cookbook: Recipes for Developers
Sveta Smirnova
 
MySQL Performance for DevOps
Sveta Smirnova
 
MySQL Test Framework для поддержки клиентов и верификации багов
Sveta Smirnova
 
MySQL Cookbook: Recipes for Your Business
Sveta Smirnova
 
Производительность MySQL для DevOps
Sveta Smirnova
 
MySQL Performance for DevOps
Sveta Smirnova
 
How to Avoid Pitfalls in Schema Upgrade with Percona XtraDB Cluster
Sveta Smirnova
 
How to migrate from MySQL to MariaDB without tears
Sveta Smirnova
 
Modern solutions for modern database load: improvements in the latest MariaDB...
Sveta Smirnova
 
How Safe is Asynchronous Master-Master Setup?
Sveta Smirnova
 
Современному хайлоду - современные решения: MySQL 8.0 и улучшения Percona
Sveta Smirnova
 
How to Avoid Pitfalls in Schema Upgrade with Galera
Sveta Smirnova
 
How Safe is Asynchronous Master-Master Setup?
Sveta Smirnova
 
Billion Goods in Few Categories: How Histograms Save a Life?
Sveta Smirnova
 
A Billion Goods in a Few Categories: When Optimizer Histograms Help and When ...
Sveta Smirnova
 
Что нужно знать о трёх топовых фичах MySQL
Sveta Smirnova
 

Recently uploaded (20)

PDF
Automate Cybersecurity Tasks with Python
VICTOR MAESTRE RAMIREZ
 
PDF
Powering GIS with FME and VertiGIS - Peak of Data & AI 2025
Safe Software
 
PPTX
MiniTool Power Data Recovery Full Crack Latest 2025
muhammadgurbazkhan
 
PDF
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
PPTX
Platform for Enterprise Solution - Java EE5
abhishekoza1981
 
PDF
Efficient, Automated Claims Processing Software for Insurers
Insurance Tech Services
 
PDF
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
PDF
Capcut Pro Crack For PC Latest Version {Fully Unlocked} 2025
hashhshs786
 
PPTX
Tally software_Introduction_Presentation
AditiBansal54083
 
PPTX
An Introduction to ZAP by Checkmarx - Official Version
Simon Bennetts
 
PDF
Understanding the Need for Systemic Change in Open Source Through Intersectio...
Imma Valls Bernaus
 
PPTX
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
PDF
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
PDF
Alexander Marshalov - How to use AI Assistants with your Monitoring system Q2...
VictoriaMetrics
 
PDF
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
PPTX
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
PDF
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
PPTX
Human Resources Information System (HRIS)
Amity University, Patna
 
PDF
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
PPTX
Java Native Memory Leaks: The Hidden Villain Behind JVM Performance Issues
Tier1 app
 
Automate Cybersecurity Tasks with Python
VICTOR MAESTRE RAMIREZ
 
Powering GIS with FME and VertiGIS - Peak of Data & AI 2025
Safe Software
 
MiniTool Power Data Recovery Full Crack Latest 2025
muhammadgurbazkhan
 
유니티에서 Burst Compiler+ThreadedJobs+SIMD 적용사례
Seongdae Kim
 
Platform for Enterprise Solution - Java EE5
abhishekoza1981
 
Efficient, Automated Claims Processing Software for Insurers
Insurance Tech Services
 
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
Capcut Pro Crack For PC Latest Version {Fully Unlocked} 2025
hashhshs786
 
Tally software_Introduction_Presentation
AditiBansal54083
 
An Introduction to ZAP by Checkmarx - Official Version
Simon Bennetts
 
Understanding the Need for Systemic Change in Open Source Through Intersectio...
Imma Valls Bernaus
 
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
MiniTool Partition Wizard 12.8 Crack License Key LATEST
hashhshs786
 
Alexander Marshalov - How to use AI Assistants with your Monitoring system Q2...
VictoriaMetrics
 
Why Businesses Are Switching to Open Source Alternatives to Crystal Reports.pdf
Varsha Nayak
 
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
Human Resources Information System (HRIS)
Amity University, Patna
 
HiHelloHR – Simplify HR Operations for Modern Workplaces
HiHelloHR
 
Java Native Memory Leaks: The Hidden Villain Behind JVM Performance Issues
Tier1 app
 

Introducing new SQL syntax and improving performance with preparse Query Rewrite Plugins

  • 1. Preparse Query Rewrite Plugins New SQL syntax for fun & performance Sveta Smirnova Principal Support Engineer January, 30, 2016
  • 2. Table of Contents •Introducing new SQL syntax •Working with results •Variables •Summary 2 www.percona.com
  • 4. MySQL often receives blames • From mascots and from humans 4 www.percona.com
  • 5. MySQL often receives blames • From mascots and from humans • It cannot make a toast 4 www.percona.com
  • 6. MySQL often receives blames • From mascots and from humans • It cannot make a toast • It does not support some syntax 4 www.percona.com
  • 7. Or does it? • FILTER clause in MySQL on my home machine 5 www.percona.com
  • 8. Or does it? • FILTER clause in MySQL on my home machine 5 www.percona.com
  • 9. Or does it? • FILTER clause in MySQL on my home machine • But not in the user manual 5 www.percona.com
  • 10. How is it done? • With 181 lines of code • Including comments! • And new Query Rewrite Plugin interface 6 www.percona.com
  • 11. A little bit of history • First introduced in version 5.7.5 • Was available at MySQL Labs • Two types of plugins • Pre-parse • Post-parse 7 www.percona.com
  • 12. Today • Part of Audit plugin interface • Step in at • MYSQL AUDIT GENERAL ALL • MYSQL AUDIT CONNECTION ALL • MYSQL AUDIT PARSE ALL • MYSQL AUDIT PARSE PREPARSE • MYSQL AUDIT PARSE POSTPARSE • MYSQL AUDIT AUTHORIZATION ALL • ... 8 www.percona.com
  • 13. Plugin skeleton #include <mysql/plugin.h> #include <mysql/plugin_audit.h> - Audit plugin declaration ... static MYSQL_PLUGIN plugin_info_ptr; - Pointer to the plugin ... static int filter_plugin_init(MYSQL_PLUGIN plugin_ref); - Plugin initialization ... static int filter(MYSQL_THD thd, mysql_event_class_t event_class, const void *event); - Entry point for MYSQL_AUDIT_PARSE_PREPARSE ... static st_mysql_audit filter_plugin_descriptor; ... mysql_declare_plugin(filter_plugin); 9 www.percona.com
  • 14. Plugin descriptor static st_mysql_audit filter_plugin_descriptor= { MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */ NULL, filter, /* implements FILTER */ // You can also use MYSQL_AUDIT_PARSE_ALL { 0, 0, (unsigned long) MYSQL_AUDIT_PARSE_PREPARSE,} }; 10 www.percona.com
  • 15. Plugin declaration mysql_declare_plugin(filter_plugin) { MYSQL_AUDIT_PLUGIN, &filter_plugin_descriptor, "filter_plugin", "Sveta Smirnova", "FILTER SQL:2003 support for MySQL", PLUGIN_LICENSE_GPL, filter_plugin_init, NULL, /* filter_plugin_deinit - TODO */ 0x0001, /* version 0.0.1 */ NULL, /* status variables */ NULL, /* system variables */ NULL, /* config options */ 0, /* flags */ } mysql_declare_plugin_end; 11 www.percona.com
  • 16. Memory management for plugins #include <my_thread.h> // my_thread_handle needed by mysql_memory.h #include <mysql/psi/mysql_memory.h> ... static PSI_memory_key key_memory_filter; static PSI_memory_info all_rewrite_memory[]= { { &key_memory_filter, "filter", 0 } }; static int filter_plugin_init(MYSQL_PLUGIN plugin_ref) { plugin_info_ptr= plugin_ref; const char* category= "sql"; int count; count= array_elements(all_rewrite_memory); mysql_memory_register(category, all_rewrite_memory, count); return 0; /* success */ } 12 www.percona.com
  • 17. SQL:2003 <filter clause> ::= FILTER <left paren> WHERE <search condition> <right paren> (10.9 <aggregate function>, 5WD-02-Foundation-2003-09.pdf, p.505) Only for aggregate functions: <computational operation> ::= AVG | MAX | MIN | SUM | EVERY | ANY | SOME | COUNT | STDDEV_POP | STDDEV_SAMP | VAR_SAMP | VAR_POP | COLLECT | FUSION | INTERSECTION <set quantifier> ::= DISTINCT | ALL MySQL only supports COUNT | AVG | SUM | MAX | MIN | STDDEV_POP | STDDEV_SAMP | VAR_SAMP | VAR_POP 13 www.percona.com
  • 18. Implementing FILTER clause • FILTER is practically CASE WHEN foo THEN bar ELSE NULL • So we only need to catch FUNCTION(var) FILTER(WHERE foo) • And replace it with CASE 14 www.percona.com
  • 19. Catching up the query static int filter(MYSQL_THD thd, // MySQL Thread object mysql_event_class_t event_class, // Class of the event const void *event // Event itself ) { const struct mysql_event_parse *event_parse= static_cast<const struct mysql_event_parse *>(event); if (event_parse->event_subclass != MYSQL_AUDIT_PARSE_PREPARSE) return 0; string subject= event_parse->query.str; // Original query string rewritten_query; //requires std::regex and GCC 4.9+ regex filter_clause_star("(COUNT)((s**s*))s+" + "FILTERs*(s*WHEREs+([^)]+)s*)", ECMAScript | icase); rewritten_query= regex_replace(subject, filter_clause_star, "$1(CASE WHEN $3 THEN 1 ELSE NULL END)"); ... 15 www.percona.com
  • 20. Rewritten query void _rewrite_query(const void *event, const struct mysql_event_parse *event_parse, char const* new_query ) { char *rewritten_query= static_cast<char *>(my_malloc( key_memory_filter, strlen(new_query) + 1, MYF(0))); strncpy(rewritten_query, new_query, strlen(new_query)); rewritten_query[strlen(new_query)]= ’0’; event_parse->rewritten_query->str= rewritten_query; // Rewritten query event_parse->rewritten_query->length=strlen(new_query); // You must set this flag to inform MySQL Server what query was rewritten *((int *)event_parse->flags)|= (int)MYSQL_AUDIT_PARSE_REWRITE_PLUGIN_QUERY_REWRITTEN; } 16 www.percona.com
  • 22. Can we do better? • Playing with syntax is fun • But can we introduce something more MySQL-ish? 18 www.percona.com
  • 23. Custom hint plugin • MySQL 5.7 has Optimizer Hints SELECT /*+ NO_RANGE_OPTIMIZATION(t3 PRIMARY, f2_idx) */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33; SELECT /*+ BKA(t1) NO_BKA(t2) */ * FROM t1 INNER JOIN t2 WHERE ...; SELECT /*+ NO_ICP(t1, t2) */ * FROM t1 INNER JOIN t2 WHERE ...; SELECT /*+ SEMIJOIN(FIRSTMATCH, LOOSESCAN) */ * FROM t1 ...; EXPLAIN SELECT /*+ NO_ICP(t1) */ * FROM t1 WHERE ...; 19 www.percona.com
  • 24. Custom hint plugin • MySQL 5.7 has Optimizer Hints • But sometimes thread-specific buffers affect query execution • Common workaround exists: SET tmp_table_size=1073741824; SELECT * FROM t1 INNER JOIN t2 WHERE ...; SET tmp_table_size=DEFAULT; • Workaround requires processing result set of each of these statements 19 www.percona.com
  • 25. Custom hint plugin • MySQL 5.7 has Optimizer Hints • But sometimes thread-specific buffers affect query execution • Workaround requires processing result set of each of these statements • This is why I extended optimizer hint syntax SELECT /*+ join_buffer_size=16384 */ f1 FROM t3 WHERE f1 > 30 AND f1 < 33; SELECT /*+ tmp_table_size=1073741824 BKA(t1) NO_BKA(t2) */ * FROM t1 INNER JOIN t2 WHERE ...; 19 www.percona.com
  • 26. New features • For Custom Hints we need to: • Store previous values of thread variables we are going to modify • Modify variables • Revert them back before sending result 20 www.percona.com
  • 27. Store previous values // map to store modified variables static map <my_thread_id, map<supported_hints_t, ulonglong> > modified_variables; ... /* The job */ static int custom_hint(MYSQL_THD thd, mysql_event_class_t event_class, const void *event) { ... // If we have a match store create map of thread variables std::map<supported_hints_t, ulonglong> current; ... After processing variables store them in modified_variables map modified_variables[thd->thread_id()]= current; ... 21 www.percona.com
  • 28. Modify variables • Since we have access to MYSQL THD this is easy: switch(get_hint_switch(ssm[1])) { case JOIN_BUFFER_SIZE: current[JOIN_BUFFER_SIZE]= thd->variables.join_buff_size; thd->variables.join_buff_size= stoull(ssm[2]); break; case TMP_TABLE_SIZE: current[TMP_TABLE_SIZE]= thd->variables.tmp_table_size; thd->variables.tmp_table_size= stoull(ssm[2]); break; ... 22 www.percona.com
  • 29. Revert variables back • First we need to tell plugin descriptor what we need MYSQL AUDIT GENERAL RESULT static st_mysql_audit custom_hint_plugin_descriptor= { MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */ NULL, custom_hint, /* implements custom hints */ { (unsigned long) MYSQL_AUDIT_GENERAL_RESULT, 0, (unsigned long) MYSQL_AUDIT_PARSE_PREPARSE, } }; 23 www.percona.com
  • 30. Revert variables back • First we need to tell plugin descriptor what we need MYSQL AUDIT GENERAL RESULT • Then revert variables before sending result if (event_general->event_subclass == MYSQL_AUDIT_GENERAL_RESULT) { map<my_thread_id, map<supported_hints_t, ulonglong> >::iterator current= modified_variables.find(thd->thread_id()); if (current != modified_variables.end()) { for (map<supported_hints_t, ulonglong>::iterator it= current->second.begin(); it!= current->second.end(); ++it) { switch(it->first) { case JOIN_BUFFER_SIZE: thd->variables.join_buff_size= it->second; break; 23 www.percona.com
  • 31. Revert variables back • First we need to tell plugin descriptor what we need MYSQL AUDIT GENERAL RESULT • Then revert variables before sending result • And, finally, erase stored values for current thread: modified_variables.erase(current); 23 www.percona.com
  • 32. Before Custom Hint Plugin mysql> flush status; Query OK, 0 rows affected (0.00 sec) mysql> select count(*), sum(c) from -> (select s, count(s) c from joinit where i < 1000000 group by s) t; +----------+--------+ | count(*) | sum(c) | +----------+--------+ | 737882 | 737882 | +----------+--------+ 1 row in set (24.70 sec) mysql> show status like ’Created_tmp_disk_tables’; +-------------------------+-------+ | Variable_name | Value | +-------------------------+-------+ | Created_tmp_disk_tables | 2 | -- 2 temporary tables on disk +-------------------------+-------+ 1 row in set (0.00 sec) 24 www.percona.com
  • 33. Custom Hint Plugin at work mysql> flush status; Query OK, 0 rows affected (0.00 sec) mysql> select /*+ tmp_table_size=134217728 max_heap_table_size=134217728 */ -> count(*), sum(c) from -> (select s, count(s) c from joinit where i < 1000000 group by s) t; +----------+--------+ | count(*) | sum(c) | +----------+--------+ | 737882 | 737882 | +----------+--------+ 1 row in set, 2 warnings (6.21 sec) -- 4 times speed gain! mysql> show status like ’Created_tmp_disk_tables’; +-------------------------+-------+ | Variable_name | Value | +-------------------------+-------+ | Created_tmp_disk_tables | 0 | -- No disk-based temporary table! +-------------------------+-------+ 1 row in set (0.00 sec) 25 www.percona.com
  • 35. BACKUP DATABASE plugin • Very simple syntax • mysql> BACKUP SERVER; +---------------------------------+ | Backup finished with status OK! | +---------------------------------+ | Backup finished with status OK! | +---------------------------------+ 1 row in set, 1 warning (42.92 sec) 27 www.percona.com
  • 36. BACKUP DATABASE plugin • Very simple syntax • Supports many tools • mysqldump • mysqlpump • mysqlbackup • XtraBackup - Planned! 27 www.percona.com
  • 37. BACKUP DATABASE plugin • Very simple syntax • Supports many tools • Needs to pass options • Credentials • Backup directory • Custom 27 www.percona.com
  • 38. Customization: credentials • We have access to • MYSQL_THR->security_context • thd->security_context()->user().str • Password still has to be in the configuration file, under [client] or [toolname] section • System variables • Since we are interested in backing up local server we will use mysqld_unix_port 28 www.percona.com
  • 39. Customization: variables • Global variables - Example only! static MYSQL_SYSVAR_STR(backup_dir, backup_dir_value, PLUGIN_VAR_MEMALLOC, "Default directory...", NULL, NULL, NULL); static MYSQL_SYSVAR_ENUM(backup_tool, backup_tool_name, PLUGIN_VAR_RQCMDARG, "Backup tool. Possible values: mysqldump|mysqlbackup", NULL, NULL, MYSQLDUMP, &supported_tools_typelib); • Thread variables • Add to plugin declaration 29 www.percona.com
  • 40. Customization: variables • Global variables - Example only! • Thread variables static MYSQL_THDVAR_STR(backup_dir, PLUGIN_VAR_MEMALLOC, "Default directory...", NULL, NULL, NULL); static MYSQL_THDVAR_ENUM(backup_tool, PLUGIN_VAR_RQCMDARG, "Backup tool. Possible values: mysqldump|mysqlbackup|mysqlpump", NULL, NULL, MYSQLDUMP, &supported_tools_typelib); ... • Add to plugin declaration 29 www.percona.com
  • 41. Customization: variables • Global variables - Example only! • Thread variables • Add to plugin declaration static struct st_mysql_sys_var *mysqlbackup_plugin_sys_vars[] = { MYSQL_SYSVAR(backup_dir), MYSQL_SYSVAR(backup_tool), MYSQL_SYSVAR(backup_tool_basedir), MYSQL_SYSVAR(backup_tool_options), NULL }; mysql_declare_plugin(mysqlbackup_plugin) { MYSQL_AUDIT_PLUGIN, &mysqlbackup_plugin_descriptor, "mysqlbackup_plugin", ... NULL, /* status variables */ mysqlbackup_plugin_sys_vars, /* system variables */ ... 29 www.percona.com
  • 43. More possibilities • Custom locks • Access to thread- and server-specific variables • Fine control at multiple steps of query execution • More 31 www.percona.com
  • 44. Code • https://github.com/svetasmirnova/ • filter plugin • custom hint plugin • mysqlbackup plugin 32 www.percona.com
  • 45. More information • MySQL source dir/plugin • rewriter • rewrite example • Writing Audit Plugins manual • MySQL Services for Plugins manual 33 www.percona.com
  • 46. Place for your questions ??? 34 www.percona.com