This task is to allow storage engines that can execute GROUP BY
queries efficiently to intercept a full query or sub query from
MariaDB and deliver the result either to the client or to a temporary
table for further processing.
The interface is using a new 'group_by_handler' class. The new class
is needed as the original query may contain multiple tables and the
'result row' can contain fields from different tables.
Overview
During prepare, call the storage engine handlerton to ask if the storage engine can execute the group by query.
If yes:
The handlerton returns a group_by_handler object.
Create a temporary table to store result rows.
Initialize the group_by_handler with the temporary table and other relevant objects
When doing 'optimize', don't optimize join order (not needed)
When do_select() is called, if we have a group_by_handler object, the following is done, instead of the normal procedure of reading things rows by row and joining tables:
Initialize group_by_handler
While get_next_row(), returns false:
Depending on context, write temporary_table->record[0] to the temporary table or return it to the next level (normally the end user).
finish group_by_handler
Note that the above loop can be executed many times, in case of
prepared statements or sub queries.
When cleanup up SELECT_LEX, we will free the group_by_handler object.
More details
Assumptions when this interface is used:
The SELECT is a GROUP BY or summary query.
All tables used in SELECT comes from the same storage engine.
This function should return a group_by_handler object if the storage engine can resolve the query itself.
New group_by_handler class with the following data and virtual methods:
TABLE *temporary_table;
Item *having;
ORDER *order_by;
/*
Store pointer to temporary table and objects modified to point to
the temporary table. This will happen during the prepare phase.
Return 1 if the storage handler cannot handle the GROUP BY after all,
in which case we fall back to normal query execution.
*/
bool init(TABLE *temporary_table, Item *having, ORDER *order_by);
/*
Bit's of things the storage engine can do. Should be initialized on
object creation.
*/
#define GROUP_BY_ORDER_BY 1 /* Result data is sorted */
uint flags;
bool init_scan();
/* Return next row result in temporary_table
bool next_row();
bool end_scan();
If the group_by_handler can't do the sorting, MariaDB will do this. Note that we assume that the handler can filter out things not matching HAVING (by calling having->val_bool()).
In the future we will look at doing a more abstract interface so that the storage engine doesn't have to understand the SELECT_LEX and other structures.
Notes from irc discussion about adding EXPLAIN support:
For first step, EXPLAIN will show one line with extra="executed by the storage engine" for the whole SELECT. (It would be nice to show the query plan that the storage engine is using, but fitting storage engine's query plans into EXPLAIN output form may be difficult. So, we're leaving this outside of scope of this MDEV).
Code-wise:
JOIN should have some data member that will mean that all join is pushed to the storage engine.
JOIN::save_explain_data_intern() should save this info in Explain_select object. Please look at this code
int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
bool need_order, bool distinct,
const char *message)
{
...
if (message)
{
Explain_select *xpl_sel;
explain_node= xpl_sel= new (output->mem_root) Explain_select;
There should be also "if (join_is_executed_by_storage_engine) " which should do the same as "if (message)
{ ...}
" does - create an Explain_select object, and xpl_sel->message="Executed by storage engine".
This should be sufficient for [SHOW] EXPLAIN to work.
Sergei Petrunia
added a comment - - edited Notes from irc discussion about adding EXPLAIN support:
For first step, EXPLAIN will show one line with extra="executed by the storage engine" for the whole SELECT. (It would be nice to show the query plan that the storage engine is using, but fitting storage engine's query plans into EXPLAIN output form may be difficult. So, we're leaving this outside of scope of this MDEV).
Code-wise:
JOIN should have some data member that will mean that all join is pushed to the storage engine.
JOIN::save_explain_data_intern() should save this info in Explain_select object. Please look at this code
int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
bool need_order, bool distinct,
const char *message)
{
...
if (message)
{
Explain_select *xpl_sel;
explain_node= xpl_sel= new (output->mem_root) Explain_select;
join->select_lex->set_explain_type(true);
xpl_sel->select_id= join->select_lex->select_number;
xpl_sel->select_type= join->select_lex->type;
xpl_sel->message= message;
...
There should be also "if (join_is_executed_by_storage_engine) " which should do the same as "if (message)
{ ...}
" does - create an Explain_select object, and xpl_sel->message="Executed by storage engine".
This should be sufficient for [SHOW] EXPLAIN to work.
The code is now pushed into
bzr+ssh://bazaar.launchpad.net/~maria-captains/maria/10.0-monty
The plan is to merge this with 10.1 as soon as this is properly reviewed.
If you have have any suggestions of how to extend or modify this interface or even suggestions for a better interface, please write your comments here!
Michael Widenius
added a comment - The code is now pushed into
bzr+ssh://bazaar.launchpad.net/~maria-captains/maria/10.0-monty
The plan is to merge this with 10.1 as soon as this is properly reviewed.
If you have have any suggestions of how to extend or modify this interface or even suggestions for a better interface, please write your comments here!
People
Sergei Golubchik
Michael Widenius
Votes:
1Vote for this issue
Watchers:
6Start watching this issue
Dates
Created:
Updated:
Resolved:
Git Integration
Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.
{"report":{"fcp":1304.1999999955297,"ttfb":339.69999999552965,"pageVisibility":"visible","entityId":35025,"key":"jira.project.issue.view-issue","isInitial":true,"threshold":1000,"elementTimings":{},"userDeviceMemory":8,"userDeviceProcessors":64,"apdex":0.5,"journeyId":"458f3425-3ec6-454b-84d2-c6b08ca24857","navigationType":0,"readyForUser":1384.2999999970198,"redirectCount":0,"resourceLoadedEnd":1609.5999999940395,"resourceLoadedStart":345.5,"resourceTiming":[{"duration":426.5,"initiatorType":"link","name":"https://jira.mariadb.org/s/2c21342762a6a02add1c328bed317ffd-CDN/lu2bv2/820016/12ta74/0a8bac35585be7fc6c9cc5a0464cd4cf/_/download/contextbatch/css/_super/batch.css","startTime":345.5,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":345.5,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":772,"responseStart":0,"secureConnectionStart":0},{"duration":426.5,"initiatorType":"link","name":"https://jira.mariadb.org/s/7ebd35e77e471bc30ff0eba799ebc151-CDN/lu2bv2/820016/12ta74/2380add21a9a1006587582385952de73/_/download/contextbatch/css/jira.browse.project,project.issue.navigator,jira.view.issue,jira.general,jira.global,atl.general,-_super/batch.css?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&slack-enabled=true","startTime":345.79999999701977,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":345.79999999701977,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":772.2999999970198,"responseStart":0,"secureConnectionStart":0},{"duration":481.79999999701977,"initiatorType":"script","name":"https://jira.mariadb.org/s/e9b27a47da5fb0f74a35acd57e9847fb-CDN/lu2bv2/820016/12ta74/0a8bac35585be7fc6c9cc5a0464cd4cf/_/download/contextbatch/js/_super/batch.js?locale=en","startTime":346,"connectEnd":346,"connectStart":346,"domainLookupEnd":346,"domainLookupStart":346,"fetchStart":346,"redirectEnd":0,"redirectStart":0,"requestStart":346,"responseEnd":827.7999999970198,"responseStart":827.7999999970198,"secureConnectionStart":346},{"duration":538.5,"initiatorType":"script","name":"https://jira.mariadb.org/s/c32eb0da7ad9831253f8397e6cc26afd-CDN/lu2bv2/820016/12ta74/2380add21a9a1006587582385952de73/_/download/contextbatch/js/jira.browse.project,project.issue.navigator,jira.view.issue,jira.general,jira.global,atl.general,-_super/batch.js?agile_global_admin_condition=true&jag=true&jira.create.linked.issue=true&locale=en&slack-enabled=true","startTime":346.19999999552965,"connectEnd":346.19999999552965,"connectStart":346.19999999552965,"domainLookupEnd":346.19999999552965,"domainLookupStart":346.19999999552965,"fetchStart":346.19999999552965,"redirectEnd":0,"redirectStart":0,"requestStart":346.19999999552965,"responseEnd":884.6999999955297,"responseStart":884.6999999955297,"secureConnectionStart":346.19999999552965},{"duration":542.2999999970198,"initiatorType":"script","name":"https://jira.mariadb.org/s/bc0bcb146314416123c992714ee00ff7-CDN/lu2bv2/820016/12ta74/c92c0caa9a024ae85b0ebdbed7fb4bd7/_/download/contextbatch/js/atl.global,-_super/batch.js?locale=en","startTime":346.29999999701977,"connectEnd":346.29999999701977,"connectStart":346.29999999701977,"domainLookupEnd":346.29999999701977,"domainLookupStart":346.29999999701977,"fetchStart":346.29999999701977,"redirectEnd":0,"redirectStart":0,"requestStart":346.29999999701977,"responseEnd":888.5999999940395,"responseStart":888.5999999940395,"secureConnectionStart":346.29999999701977},{"duration":542.6999999955297,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bv2/820016/12ta74/1.0/_/download/batch/jira.webresources:calendar-en/jira.webresources:calendar-en.js","startTime":346.5,"connectEnd":346.5,"connectStart":346.5,"domainLookupEnd":346.5,"domainLookupStart":346.5,"fetchStart":346.5,"redirectEnd":0,"redirectStart":0,"requestStart":346.5,"responseEnd":889.1999999955297,"responseStart":889.1999999955297,"secureConnectionStart":346.5},{"duration":543.1000000014901,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bv2/820016/12ta74/1.0/_/download/batch/jira.webresources:calendar-localisation-moment/jira.webresources:calendar-localisation-moment.js","startTime":346.69999999552965,"connectEnd":346.69999999552965,"connectStart":346.69999999552965,"domainLookupEnd":346.69999999552965,"domainLookupStart":346.69999999552965,"fetchStart":346.69999999552965,"redirectEnd":0,"redirectStart":0,"requestStart":346.69999999552965,"responseEnd":889.7999999970198,"responseStart":889.7999999970198,"secureConnectionStart":346.69999999552965},{"duration":624,"initiatorType":"link","name":"https://jira.mariadb.org/s/b04b06a02d1959df322d9cded3aeecc1-CDN/lu2bv2/820016/12ta74/a2ff6aa845ffc9a1d22fe23d9ee791fc/_/download/contextbatch/css/jira.global.look-and-feel,-_super/batch.css","startTime":346.8999999985099,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":346.8999999985099,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":970.8999999985099,"responseStart":0,"secureConnectionStart":0},{"duration":543.3000000044703,"initiatorType":"script","name":"https://jira.mariadb.org/rest/api/1.0/shortcuts/820016/47140b6e0a9bc2e4913da06536125810/shortcuts.js?context=issuenavigation&context=issueaction","startTime":347.09999999403954,"connectEnd":347.09999999403954,"connectStart":347.09999999403954,"domainLookupEnd":347.09999999403954,"domainLookupStart":347.09999999403954,"fetchStart":347.09999999403954,"redirectEnd":0,"redirectStart":0,"requestStart":347.09999999403954,"responseEnd":890.3999999985099,"responseStart":890.3999999985099,"secureConnectionStart":347.09999999403954},{"duration":623.8000000044703,"initiatorType":"link","name":"https://jira.mariadb.org/s/3ac36323ba5e4eb0af2aa7ac7211b4bb-CDN/lu2bv2/820016/12ta74/d176f0986478cc64f24226b3d20c140d/_/download/contextbatch/css/com.atlassian.jira.projects.sidebar.init,-_super,-project.issue.navigator,-jira.view.issue/batch.css?jira.create.linked.issue=true","startTime":347.19999999552965,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":347.19999999552965,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":971,"responseStart":0,"secureConnectionStart":0},{"duration":543.6000000014901,"initiatorType":"script","name":"https://jira.mariadb.org/s/719848dd97ebe0663199f49a3936487a-CDN/lu2bv2/820016/12ta74/d176f0986478cc64f24226b3d20c140d/_/download/contextbatch/js/com.atlassian.jira.projects.sidebar.init,-_super,-project.issue.navigator,-jira.view.issue/batch.js?jira.create.linked.issue=true&locale=en","startTime":347.3999999985099,"connectEnd":347.3999999985099,"connectStart":347.3999999985099,"domainLookupEnd":347.3999999985099,"domainLookupStart":347.3999999985099,"fetchStart":347.3999999985099,"redirectEnd":0,"redirectStart":0,"requestStart":347.3999999985099,"responseEnd":891,"responseStart":891,"secureConnectionStart":347.3999999985099},{"duration":986.1000000014901,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bv2/820016/12ta74/1.0/_/download/batch/jira.webresources:bigpipe-js/jira.webresources:bigpipe-js.js","startTime":352.8999999985099,"connectEnd":352.8999999985099,"connectStart":352.8999999985099,"domainLookupEnd":352.8999999985099,"domainLookupStart":352.8999999985099,"fetchStart":352.8999999985099,"redirectEnd":0,"redirectStart":0,"requestStart":352.8999999985099,"responseEnd":1339,"responseStart":1339,"secureConnectionStart":352.8999999985099},{"duration":1256.6999999955297,"initiatorType":"script","name":"https://jira.mariadb.org/s/d41d8cd98f00b204e9800998ecf8427e-CDN/lu2bv2/820016/12ta74/1.0/_/download/batch/jira.webresources:bigpipe-init/jira.webresources:bigpipe-init.js","startTime":352.8999999985099,"connectEnd":352.8999999985099,"connectStart":352.8999999985099,"domainLookupEnd":352.8999999985099,"domainLookupStart":352.8999999985099,"fetchStart":352.8999999985099,"redirectEnd":0,"redirectStart":0,"requestStart":352.8999999985099,"responseEnd":1609.5999999940395,"responseStart":1609.5999999940395,"secureConnectionStart":352.8999999985099},{"duration":356.5,"initiatorType":"xmlhttprequest","name":"https://jira.mariadb.org/rest/webResources/1.0/resources","startTime":984,"connectEnd":984,"connectStart":984,"domainLookupEnd":984,"domainLookupStart":984,"fetchStart":984,"redirectEnd":0,"redirectStart":0,"requestStart":984,"responseEnd":1340.5,"responseStart":1340.5,"secureConnectionStart":984},{"duration":327.79999999701977,"initiatorType":"script","name":"https://www.google-analytics.com/analytics.js","startTime":1297.3999999985099,"connectEnd":0,"connectStart":0,"domainLookupEnd":0,"domainLookupStart":0,"fetchStart":1297.3999999985099,"redirectEnd":0,"redirectStart":0,"requestStart":0,"responseEnd":1625.1999999955297,"responseStart":0,"secureConnectionStart":0}],"fetchStart":0,"domainLookupStart":0,"domainLookupEnd":0,"connectStart":0,"connectEnd":0,"requestStart":170,"responseStart":340,"responseEnd":351,"domLoading":344,"domInteractive":1647,"domContentLoadedEventStart":1647,"domContentLoadedEventEnd":1692,"domComplete":2289,"loadEventStart":2289,"loadEventEnd":2290,"userAgent":"Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)","marks":[{"name":"bigPipe.sidebar-id.start","time":1627},{"name":"bigPipe.sidebar-id.end","time":1627.7999999970198},{"name":"bigPipe.activity-panel-pipe-id.start","time":1628},{"name":"bigPipe.activity-panel-pipe-id.end","time":1629.5},{"name":"activityTabFullyLoaded","time":1739.8999999985099}],"measures":[],"correlationId":"d3d9b7e959de6d","effectiveType":"4g","downlink":10,"rtt":0,"serverDuration":109,"dbReadsTimeInMs":12,"dbConnsTimeInMs":21,"applicationHash":"9d11dbea5f4be3d4cc21f03a88dd11d8c8687422","experiments":[]}}
Notes from irc discussion about adding EXPLAIN support:
For first step, EXPLAIN will show one line with extra="executed by the storage engine" for the whole SELECT. (It would be nice to show the query plan that the storage engine is using, but fitting storage engine's query plans into EXPLAIN output form may be difficult. So, we're leaving this outside of scope of this MDEV).
Code-wise:
int JOIN::save_explain_data_intern(Explain_query *output, bool need_tmp_table,
bool need_order, bool distinct,
const char *message)
{
...
if (message)
{
Explain_select *xpl_sel;
explain_node= xpl_sel= new (output->mem_root) Explain_select;
join->select_lex->set_explain_type(true);
xpl_sel->select_id= join->select_lex->select_number;
xpl_sel->select_type= join->select_lex->type;
xpl_sel->message= message;
...
There should be also "if (join_is_executed_by_storage_engine) " which should do the same as "if (message)
{ ...}" does - create an Explain_select object, and xpl_sel->message="Executed by storage engine".
This should be sufficient for [SHOW] EXPLAIN to work.