Details
-
Task
-
Status: Closed (View Workflow)
-
Major
-
Resolution: Fixed
-
None
Description
(Documentation is at https://mariadb.com/kb/en/analyze-statement/)
== SQL syntax ==
The new syntax:
ANALYZE $explainable_stmt
|
ANALYZE $stmt will run the $stmt, and produce the output that EXPLAIN $stmt would produce, annotated with info about the query execution.
== Adjustments to EXPLAIN output ==
EXPLAIN FORMAT=JSON is easy to extend.
As for tabular EXPLAIN form, the following columns will be added:
- loops ( need this?)
- r_rows
- r_filtered
== Implementation at SQL layer ==
The parser will set LEX::analyze_stmt flag for ANALYZE statements.
There is LEX::describe which stores flags about EXPLAIN EXTENDED|PARTITIONS
but it is used to check whether the query is an EXPLAIN or not, and ANALYZE
command is not an EXPLAIN, because it actually runs the query.
Note: ANALYZE UPDATE statement actually makes the updates. With SBR, we will
have to write the statement into the binlog. The slave must be able to execute
it (I suspect current slave will choke on a statement that produces output).
== Counting ==
We will collect two kinds of counters:
1. Some are counted at SQL level, like filtered%, ICP_filtered, #rows, etc.
2. Some will be counted deeper inside the engine, like number of disk reads per table.
The problems with the latter are
- the counters are global or per-table. We need them to be per-table-instance
(to handle self-join-like queries correctly) - They may be difficult to get from the SQL layer.
== Getting the counter values ==
This is where the new SHOW EXPLAIN architecture plays against us.
The problem is: at the end of JOIN::optimize(), the plan is saved into an
Explain_select structure, and EXPLAIN output is produced from Explain_select.
Explain_select object has only "explain" information, it has no connection to
objects that participate in query execution (like JOIN_TABs, or handler*, etc).
An apparent solution is to have JOIN::cleanup() save execution data using a
call that is similar to save_explain_data()
Attachments
Issue Links
- causes
-
MDEV-17079 Update documentation on "EXPLAIN" and "EXPLAIN in the Slow Query Log"
-
- Open
-
- relates to
-
MDEV-407 Print EXPLAIN [ANALYZE] in the slow query log
-
- Closed
-
-
MDEV-6382 ANALYZE $stmt and security
-
- Closed
-
-
MDEV-6388 ANALYZE $stmt output in the slow query log
-
- Closed
-
-
MDEV-6393 ANALYZE SELECT crashes in Explain_query::print_explain with a non-existing column
-
- Closed
-
-
MDEV-6394 ANALYZE DELETE .. RETURNING fails with ERROR 2027 Malformed packet
-
- Closed
-
-
MDEV-6395 ANALYZE UPDATE/DELETE with impossible where does not produce any output
-
- Closed
-
-
MDEV-6396 ANALYZE INSERT/REPLACE is accepted, but does not produce a plan
-
- Closed
-
-
MDEV-6397 ANALYZE SELECT/UPDATE/DELETE increments Com_select/update/delete, but not Com_analyze
-
- Closed
-
-
MDEV-6398 ANALYZE UPDATE does not populate r_rows
-
- Closed
-
-
MDEV-6400 "ANALYZE SELECT ... INTO @var" doesn't set @var
-
- Closed
-
-
MDEV-6422 More testing for ANALYZE stmt and JSON
-
- Closed
-
-
MDEV-7023 Error 2027: Malformed packet and assertion `field_types == 0 || field_types[field_pos] == MYSQL_TYPE_INT24 || field_types[field_pos] == MYSQL_TYPE_LONG' failure in Protocol_text::store_long
-
- Closed
-
-
MDEV-7024 Assertion `! is_set()' failed in Diagnostics_area::set_eof_status on executing ANALYZE SELECT via PS
-
- Closed
-
-
MDEV-7025 ANALYZE SELECT/INSERT/UPDATE/DELETE from a view does not check access permissions on the underlying table
-
- Closed
-
-
MDEV-7027 ANALYZE SELECT/INSERT/UPDATE/DELETE from a view does not check SHOW permission on the view
-
- Closed
-
-
MDEV-7117 ANALYZE SELECT produces strange r_filtered value on a query with ORDER BY
-
- Confirmed
-
-
MDEV-7115 ANALYZE SELECT FROM empty table produces a plan which looks different from EXPLAIN
-
- Open
-
Activity
Field | Original Value | New Value |
---|---|---|
Description |
In other databases, EXPLAIN ANALYZE works as follows: - It runs the select normally, discarding its output - Instead, it produces EXPLAIN's output, but cost/#rows estimates are accompanied with actual numbers measured during execution. SHOW EXPLAIN gave us ability to produce query's EXPLAIN at arbitrary point in time. This makes it possible to implement EXPLAIN ANALYZE. |
In other databases, EXPLAIN ANALYZE works as follows: - It runs the select normally, discarding its output - Instead, it produces EXPLAIN's output, but cost/#rows estimates are accompanied with actual numbers measured during execution. SHOW EXPLAIN gave us ability to produce query's EXPLAIN at arbitrary point in time. This makes it possible to implement EXPLAIN ANALYZE. == Interface == - The parser should support EXPLAIN ANALYZE syntax - EXPLAIN will produce extra columns: - after "rows" there will be "real_rows" - after "filtered" there will be "real_filtered" - there will be 'loops' column, which will tell how many times a scan was performed. == Implementation == (TODO: where do we save the flag that this is EXPLAIN_ANALYZE ? UNCACHEABLE_EXPLAIN is a bad one, because it is in every subselect... There's LEX::describe, which is a bitmap DESCRIBE{NORMAL|EXTENDED|PARTITIONS}, but it is checked in many places. We need a flag next to LEX::describe) EXPLAIN ANALYZE should be run, generally, like a regular select (and not like an EXPLAIN). The differences are: - need to prevent it from sending SELECT's column list to the client - need to prevent it from sending SELECT's data to the client - need to have individual counters for each table. We've got Handler counters and userstat counters already. Isn't it too much, perhaps we could - have one counter that we increment during the query - at query end, 'distribute' the increments to Handler_xxx, userstat, etc. - need to save each JOIN's plan before it is deleted (we need to save it 'late', so that we can get query plan + actual counter values) TODO: what/how to count for range_checked_for_each_record? |
Description |
In other databases, EXPLAIN ANALYZE works as follows: - It runs the select normally, discarding its output - Instead, it produces EXPLAIN's output, but cost/#rows estimates are accompanied with actual numbers measured during execution. SHOW EXPLAIN gave us ability to produce query's EXPLAIN at arbitrary point in time. This makes it possible to implement EXPLAIN ANALYZE. == Interface == - The parser should support EXPLAIN ANALYZE syntax - EXPLAIN will produce extra columns: - after "rows" there will be "real_rows" - after "filtered" there will be "real_filtered" - there will be 'loops' column, which will tell how many times a scan was performed. == Implementation == (TODO: where do we save the flag that this is EXPLAIN_ANALYZE ? UNCACHEABLE_EXPLAIN is a bad one, because it is in every subselect... There's LEX::describe, which is a bitmap DESCRIBE{NORMAL|EXTENDED|PARTITIONS}, but it is checked in many places. We need a flag next to LEX::describe) EXPLAIN ANALYZE should be run, generally, like a regular select (and not like an EXPLAIN). The differences are: - need to prevent it from sending SELECT's column list to the client - need to prevent it from sending SELECT's data to the client - need to have individual counters for each table. We've got Handler counters and userstat counters already. Isn't it too much, perhaps we could - have one counter that we increment during the query - at query end, 'distribute' the increments to Handler_xxx, userstat, etc. - need to save each JOIN's plan before it is deleted (we need to save it 'late', so that we can get query plan + actual counter values) TODO: what/how to count for range_checked_for_each_record? |
In other databases, EXPLAIN ANALYZE works as follows: - It runs the select normally, discarding its output - Instead, it produces EXPLAIN's output, but cost/#rows estimates are accompanied with actual numbers measured during execution. SHOW EXPLAIN gave us ability to produce query's EXPLAIN at arbitrary point in time. This makes it possible to implement EXPLAIN ANALYZE. == Interface == - The parser should support EXPLAIN ANALYZE syntax - EXPLAIN will produce extra columns: - after "rows" there will be "real_rows" - after "filtered" there will be "real_filtered" - there will be 'loops' column, which will tell how many times a scan was performed. == Implementation == (TODO: where do we save the flag that this is EXPLAIN_ANALYZE ? UNCACHEABLE_EXPLAIN is a bad one, because it is in every subselect... There's LEX::describe, which is a bitmap DESCRIBE{NORMAL|EXTENDED|PARTITIONS}, but it is checked in many places. We need a flag next to LEX::describe) EXPLAIN ANALYZE should be run, generally, like a regular select (and not like an EXPLAIN). The differences are: - need to prevent it from sending SELECT's column list to the client - need to prevent it from sending SELECT's data to the client - need to have individual counters for each table. We've got Handler counters and userstat counters already. Isn't it too much, perhaps we could -- have one counter that we increment during the query -- at query end, 'distribute' the increments to Handler_xxx, userstat, etc. - need to save each JOIN's plan before it is deleted (we need to save it 'late', so that we can get query plan + actual counter values) TODO: what/how to count for range_checked_for_each_record? |
Assignee | Sergei Petrunia [ psergey ] |
Status | Open [ 1 ] | In Progress [ 3 ] |
Description |
In other databases, EXPLAIN ANALYZE works as follows: - It runs the select normally, discarding its output - Instead, it produces EXPLAIN's output, but cost/#rows estimates are accompanied with actual numbers measured during execution. SHOW EXPLAIN gave us ability to produce query's EXPLAIN at arbitrary point in time. This makes it possible to implement EXPLAIN ANALYZE. == Interface == - The parser should support EXPLAIN ANALYZE syntax - EXPLAIN will produce extra columns: - after "rows" there will be "real_rows" - after "filtered" there will be "real_filtered" - there will be 'loops' column, which will tell how many times a scan was performed. == Implementation == (TODO: where do we save the flag that this is EXPLAIN_ANALYZE ? UNCACHEABLE_EXPLAIN is a bad one, because it is in every subselect... There's LEX::describe, which is a bitmap DESCRIBE{NORMAL|EXTENDED|PARTITIONS}, but it is checked in many places. We need a flag next to LEX::describe) EXPLAIN ANALYZE should be run, generally, like a regular select (and not like an EXPLAIN). The differences are: - need to prevent it from sending SELECT's column list to the client - need to prevent it from sending SELECT's data to the client - need to have individual counters for each table. We've got Handler counters and userstat counters already. Isn't it too much, perhaps we could -- have one counter that we increment during the query -- at query end, 'distribute' the increments to Handler_xxx, userstat, etc. - need to save each JOIN's plan before it is deleted (we need to save it 'late', so that we can get query plan + actual counter values) TODO: what/how to count for range_checked_for_each_record? |
Documentation is at: http://kb.askmonty.org/en/explain-analyze/ In other databases, EXPLAIN ANALYZE works as follows: - It runs the select normally, discarding its output - Instead, it produces EXPLAIN's output, but cost/#rows estimates are accompanied with actual numbers measured during execution. SHOW EXPLAIN gave us ability to produce query's EXPLAIN at arbitrary point in time. This makes it possible to implement EXPLAIN ANALYZE. == Interface == - The parser should support EXPLAIN ANALYZE syntax - EXPLAIN will produce extra columns: - after "rows" there will be "real_rows" - after "filtered" there will be "real_filtered" - there will be 'loops' column, which will tell how many times a scan was performed. == Implementation == (TODO: where do we save the flag that this is EXPLAIN_ANALYZE ? UNCACHEABLE_EXPLAIN is a bad one, because it is in every subselect... There's LEX::describe, which is a bitmap DESCRIBE{NORMAL|EXTENDED|PARTITIONS}, but it is checked in many places. We need a flag next to LEX::describe) EXPLAIN ANALYZE should be run, generally, like a regular select (and not like an EXPLAIN). The differences are: - need to prevent it from sending SELECT's column list to the client - need to prevent it from sending SELECT's data to the client - need to have individual counters for each table. We've got Handler counters and userstat counters already. Isn't it too much, perhaps we could -- have one counter that we increment during the query -- at query end, 'distribute' the increments to Handler_xxx, userstat, etc. - need to save each JOIN's plan before it is deleted (we need to save it 'late', so that we can get query plan + actual counter values) TODO: what/how to count for range_checked_for_each_record? |
Status | In Progress [ 3 ] | Stalled [ 10000 ] |
Fix Version/s | 10.1.0 [ 12200 ] |
Labels | optimizer |
Status | Stalled [ 10000 ] | In Progress [ 3 ] |
Description |
Documentation is at: http://kb.askmonty.org/en/explain-analyze/ In other databases, EXPLAIN ANALYZE works as follows: - It runs the select normally, discarding its output - Instead, it produces EXPLAIN's output, but cost/#rows estimates are accompanied with actual numbers measured during execution. SHOW EXPLAIN gave us ability to produce query's EXPLAIN at arbitrary point in time. This makes it possible to implement EXPLAIN ANALYZE. == Interface == - The parser should support EXPLAIN ANALYZE syntax - EXPLAIN will produce extra columns: - after "rows" there will be "real_rows" - after "filtered" there will be "real_filtered" - there will be 'loops' column, which will tell how many times a scan was performed. == Implementation == (TODO: where do we save the flag that this is EXPLAIN_ANALYZE ? UNCACHEABLE_EXPLAIN is a bad one, because it is in every subselect... There's LEX::describe, which is a bitmap DESCRIBE{NORMAL|EXTENDED|PARTITIONS}, but it is checked in many places. We need a flag next to LEX::describe) EXPLAIN ANALYZE should be run, generally, like a regular select (and not like an EXPLAIN). The differences are: - need to prevent it from sending SELECT's column list to the client - need to prevent it from sending SELECT's data to the client - need to have individual counters for each table. We've got Handler counters and userstat counters already. Isn't it too much, perhaps we could -- have one counter that we increment during the query -- at query end, 'distribute' the increments to Handler_xxx, userstat, etc. - need to save each JOIN's plan before it is deleted (we need to save it 'late', so that we can get query plan + actual counter values) TODO: what/how to count for range_checked_for_each_record? |
(Documentation for previous iteration of the feature is at http://kb.askmonty.org/en/explain-analyze/ ) h2. == SQL syntax == The new syntax: {noformat} ANALYZE $explainable_stmt {noformat} ANALYZE $stmt will run the $stmt, and produce the output that EXPLAIN $stmt would produce, annotated with info about the query execution. h2. == Adjustments to EXPLAIN output == EXPLAIN FORMAT=JSON is easy to extend. As for tabular EXPLAIN form, the following columns will be added: - loops ( need this?) - r_rows - r_filtered h2. == Implementation at SQL layer == The parser will set LEX::analyze_stmt flag for ANALYZE statements. There is LEX::describe which stores flags about EXPLAIN EXTENDED|PARTITIONS but it is used to check whether the query is an EXPLAIN or not, and ANALYZE command is not an EXPLAIN, because it actually runs the query. Note: ANALYZE UPDATE statement actually makes the updates. With SBR, we will have to write the statement into the binlog. The slave must be able to execute it (I suspect current slave will choke on a statement that produces output). h2. == Counting == We will collect two kinds of counters: 1. Some are counted at SQL level, like filtered%, ICP_filtered, #rows, etc. 2. Some will be counted deeper inside the engine, like number of disk reads per table. The problems with the latter are * the counters are global or per-table. We need them to be per-table-instance (to handle self-join-like queries correctly) * They may be difficult to get from the SQL layer. h2. == Getting the counter values == This is where the new SHOW EXPLAIN architecture plays against us. The problem is: at the end of JOIN::optimize(), the plan is saved into an Explain_select structure, and EXPLAIN output is produced from Explain_select. Explain_select object has only "explain" information, it has no connection to objects that participate in query execution (like JOIN_TABs, or handler*, etc). An apparent solution is to have JOIN::cleanup() save execution data using a call that is similar to save_explain_data() |
Summary | EXPLAIN ANALYZE | ANALYZE $stmt |
Workflow | defaullt [ 12711 ] | MariaDB v2 [ 43826 ] |
Priority | Major [ 3 ] | Critical [ 2 ] |
Priority | Critical [ 2 ] | Major [ 3 ] |
Resolution | Fixed [ 1 ] | |
Status | In Progress [ 3 ] | Closed [ 6 ] |
Description |
(Documentation for previous iteration of the feature is at http://kb.askmonty.org/en/explain-analyze/ ) h2. == SQL syntax == The new syntax: {noformat} ANALYZE $explainable_stmt {noformat} ANALYZE $stmt will run the $stmt, and produce the output that EXPLAIN $stmt would produce, annotated with info about the query execution. h2. == Adjustments to EXPLAIN output == EXPLAIN FORMAT=JSON is easy to extend. As for tabular EXPLAIN form, the following columns will be added: - loops ( need this?) - r_rows - r_filtered h2. == Implementation at SQL layer == The parser will set LEX::analyze_stmt flag for ANALYZE statements. There is LEX::describe which stores flags about EXPLAIN EXTENDED|PARTITIONS but it is used to check whether the query is an EXPLAIN or not, and ANALYZE command is not an EXPLAIN, because it actually runs the query. Note: ANALYZE UPDATE statement actually makes the updates. With SBR, we will have to write the statement into the binlog. The slave must be able to execute it (I suspect current slave will choke on a statement that produces output). h2. == Counting == We will collect two kinds of counters: 1. Some are counted at SQL level, like filtered%, ICP_filtered, #rows, etc. 2. Some will be counted deeper inside the engine, like number of disk reads per table. The problems with the latter are * the counters are global or per-table. We need them to be per-table-instance (to handle self-join-like queries correctly) * They may be difficult to get from the SQL layer. h2. == Getting the counter values == This is where the new SHOW EXPLAIN architecture plays against us. The problem is: at the end of JOIN::optimize(), the plan is saved into an Explain_select structure, and EXPLAIN output is produced from Explain_select. Explain_select object has only "explain" information, it has no connection to objects that participate in query execution (like JOIN_TABs, or handler*, etc). An apparent solution is to have JOIN::cleanup() save execution data using a call that is similar to save_explain_data() |
(Documentation is at https://mariadb.com/kb/en/analyze-statement/) h2. == SQL syntax == The new syntax: {noformat} ANALYZE $explainable_stmt {noformat} ANALYZE $stmt will run the $stmt, and produce the output that EXPLAIN $stmt would produce, annotated with info about the query execution. h2. == Adjustments to EXPLAIN output == EXPLAIN FORMAT=JSON is easy to extend. As for tabular EXPLAIN form, the following columns will be added: - loops ( need this?) - r_rows - r_filtered h2. == Implementation at SQL layer == The parser will set LEX::analyze_stmt flag for ANALYZE statements. There is LEX::describe which stores flags about EXPLAIN EXTENDED|PARTITIONS but it is used to check whether the query is an EXPLAIN or not, and ANALYZE command is not an EXPLAIN, because it actually runs the query. Note: ANALYZE UPDATE statement actually makes the updates. With SBR, we will have to write the statement into the binlog. The slave must be able to execute it (I suspect current slave will choke on a statement that produces output). h2. == Counting == We will collect two kinds of counters: 1. Some are counted at SQL level, like filtered%, ICP_filtered, #rows, etc. 2. Some will be counted deeper inside the engine, like number of disk reads per table. The problems with the latter are * the counters are global or per-table. We need them to be per-table-instance (to handle self-join-like queries correctly) * They may be difficult to get from the SQL layer. h2. == Getting the counter values == This is where the new SHOW EXPLAIN architecture plays against us. The problem is: at the end of JOIN::optimize(), the plan is saved into an Explain_select structure, and EXPLAIN output is produced from Explain_select. Explain_select object has only "explain" information, it has no connection to objects that participate in query execution (like JOIN_TABs, or handler*, etc). An apparent solution is to have JOIN::cleanup() save execution data using a call that is similar to save_explain_data() |
Labels | optimizer | analyze-stmt optimizer |
Workflow | MariaDB v2 [ 43826 ] | MariaDB v3 [ 64424 ] |
Link | This issue causes MDEV-17079 [ MDEV-17079 ] |
Workflow | MariaDB v3 [ 64424 ] | MariaDB v4 [ 131952 ] |
test=# explain select count
from one_k where ones < 10;
QUERY PLAN
-------------------------------------------------------------
Aggregate (cost=17.53..17.54 rows=1 width=0)
-> Seq Scan on one_k (cost=0.00..17.50 rows=11 width=0)
Filter: (ones < 10)
(3 rows)
test=# explain analyze select count
from one_k where ones < 10;
QUERY PLAN
--------------------------------------------------------------------------------------------------------
Aggregate (cost=17.53..17.54 rows=1 width=0) (actual time=1.449..1.451 rows=1 loops=1)
-> Seq Scan on one_k (cost=0.00..17.50 rows=11 width=0) (actual time=0.037..1.406 rows=10 loops=1)
Filter: (ones < 10)
Total runtime: 1.560 ms
(4 rows)