In this assignment, you will carry out a number of exercises involving the optimization of relational queries using the MySQL query optimizer and the visualization command EXPLAIN. You need to read some of the MySQL documentation in Section 2 to be able to complete this assignment. To be more specific, you need to be familiar with EXPLAIN, SHOW PROFILE, ANALYZE, and the INFORMATION_SCHEMA Tables commands of MySQL (specific links are provided in the subsections).
This is a small hands-on project and should be done INDIVIDUALLY. Please read the entire assignment carefully before your beginning.
- The MySQL documentation tree: http://dev.mysql.com/doc/
- The EXPLAIN Command: http://dev.mysql.com/doc/refman/8.0/en/explain.html, http://dev.mysql.com/doc/refman/8.0/en/explain-output.html, http://dev.mysql.com/doc/refman/8.0/en/cost-model.html, http://dev.mysql.com/doc/refman/8.0/en/using-explain.html
- The visual EXPLAIN in MySQL Workbench: http://dev.mysql.com/doc/workbench/en/wb-tutorial-visual-explain-dbt3.html
- The InnoDB storage system: http://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html, http://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_stats_persistent_sample_p ages
- The SHOW and SHOW PROFILE Commands: http://dev.mysql.com/doc/refman/8.0/en/show-tables.html, http://dev.mysql.com/doc/refman/8.0/en/show-columns.html, http://dev.mysql.com/doc/refman/8.0/en/show-status.html, http://dev.mysql.com/doc/refman/8.0/en/show-profile.html, http://dev.mysql.com/doc/refman/8.0/en/show-profiles.html
- The CREATE INDEX Command: http://dev.mysql.com/doc/refman/8.0/en/create-index.html
- Statistics and other information collected by MySQL, including ANALYZE and INFORMATION_SCHEMA Tables: http://dev.mysql.com/doc/refman/8.0/en/analyze-table.html, http://dev.mysql.com/doc/refman/8.0/en/innodb-persistent-stats.html, http://dev.mysql.com/doc/refman/8.0/en/information-schema.html, https://dev.mysql.com/doc/refman/8.0/en/information-schema-columns-table.html, https://dev.mysql.com/doc/mysql-infoschema-excerpt/8.0/en/information-schema-tables-table.html
You need to create a new database and create four tables in this database. We provide the definitions of the tables and the data. You can download the zip file with the table schemas and the data from Piazza.
We will use four tables in this experiment: part, supplier, partsupp, and lineitem.
- part ( p_partkey integer, p_name varchar(55), p_mfgr character(25), p_brand character(10), p_type varchar(25), p_size integer, p_container character(10), p_retailprice numeric(20,2), p_comment varchar(23), primary key (p_partkey));
- supplier ( s_suppkey integer, s_name char(25), s_address varchar(40), s_nationkey integer, s_phone character(15), s_acctbal numeric(20,2), s_comment varchar(101), primary key (s_suppkey));
- partsupp (ps_partkey integer, ps_suppkey integer, ps_availqty integer, ps_supplycost numeric(20,2), ps_comment varchar(199), primary key(ps_partkey, ps_suppkey));
- lineitem( l_orderkey integer, l_partkey integer, l_suppkey integer, l_linenumber integer, l_quantity numeric(20,2), l_extendedprice numeric(20,2), l_discount numeric(3,2), l_tax numeric(3,2), l_returnflag character(1), l_linestatus character(1), l_shipdate date, l_commitdate date, l_receiptdate date, l_shipinstruct character(25), l_shipmode character(10), l_comment varchar(44), primary key (l_orderkey, l_linenumber);
- Create a database (e.g. tpch) and create the tables. You can use the create table statements in the schema.sql file.
- Exit mysql and login again to mysql using the following command:
> mysql --local-infile -uroot -p
Modify the local-infile variable so that you can run “load data” command later:
> SET GLOBAL local_infile = true;
Check the variable “local_infile” is properly set:
> SHOW VARIABLES LIKE 'local_infile';
You should see the value of “local_infile” is “ON”
- You can load the data using the load command. To load the part table, you do (replace
“path_in_your_laptop” with the actual path that you store the data files):
> use tpch; (your database name)
> load data local infile 'path_in_your_laptop /part.tbl' into table part fields terminated by '|';
- You can see also here for more: http://dev.mysql.com/doc/refman/8.0/en/load-data.html
In general, use EXPLAIN FORMAT=JSON to get the evaluation plan because it gives much more information about the plan. Use the actual execution of the query on terminal or profile information for query execution times.
To use the Profiles, you need to set the profile on first using: SET profiling = 1;
Statistics of the Tables
We will first examine the statistics for table lineitem. Answer the following questions.
- How many records are there actually in “lineitem”? What is the estimated value by the InnoDB optimizer? How do you find these values (command or SQL)?
- Is the value used by the query optimizer accurate? If not, why?
Index on Perfect Match Query
We will check how index affects query optimization and performance.
Examine the following query:
SELECT * FROM lineitem WHERE L_TAX = 0.07;
- What is the estimated total cost of executing the best plan? What does the cost of a plan mean in MySQL?
- What is the estimated result cardinality for this plan? How does the query optimizer obtain this value? Is it a reasonable one?
- Which access method (access type) does the optimizer choose?
Create a B-Tree index “ltax_idx” on the attribute “L_TAX”.
- Which access method does the optimizer consider to be the best now? Is the estimated result cardinality better now? Why?
- Compare the two plans (with and without index). Explain briefly why the access method in 4. is cheaper than the previous one without index.
Index on Range Select
Consider the following query:
SELECT * FROM lineitem WHERE L_QUANTITY < 45;
- How many tuples does the query optimizer think will be returned? What is the estimated total cost?
- What is the access method used?
Consider now the following query:
SELECT * FROM lineitem WHERE L_QUANTITY < 3;
Now create a B-Tree index “l_qty_idx” on the attribute “L_QUANTITY”. Run “Explain” command for this query.
- What is the estimated total cost now? Does the estimated total cost make sense? Why? In what order would the tuples be returned by this plan?
- Explain why one of the access methods is more expensive than the other. [From now on, you may use “Explain current statement” functionality in workbench to check the visualized query plan]
Consider the following query:
SELECT DISTINCT (s_name)
FROM supplier, partsupp
WHERE s_suppkey = ps_suppkey AND ps_availqty < 40;
- Write down the best plan estimated by the optimizer (in plan tree form). What is the estimated total cost?
- What is the join algorithm used in the plan? Explain how the system reads the two relations (what access method is used).
- According to the optimizer, how many tuples will be retrieved from partsupp per scan? How many from supplier per scan? Do you consider these numbers a good estimation? Why or why not?
- Can you add an index to improve the performance of the query? Which index you will create and on which attribute? What is the new plan that is executed and what is its cost?
- After you created the index, check the estimation of the number of tuples retrieved from partsupp. Is it a good estimation? If yes, why?
Consider the following query:
SELECT p_name, s_name
FROM part, supplier, partsupp
WHERE s_suppkey = ps_suppkey AND p_partkey = ps_partkey;
- Write down the best plan chosen by the optimizer. List the joins and access methods it uses, and the order in which the relations are joined. What is the estimated cost of this plan? What is the actual query execution time of this query?
- Can you add an index to improve the query performance? You are free to add any index that you like on any table. What is the new plan now? What is the new estimated cost? Is the new plan really better in practice than the previous one (does the query run faster now)?
- Modify the query by adding a condition AND ps_availqty < 10 in the WHERE clause. What are the differences between the current query plan and the one in 4.5.1? Why is the current query plan more efficient than the one in 4.5.1?