SlideShare a Scribd company logo
1 of 33
Download to read offline
Understanding Query Execution


                                     Jay Pipes
                     Community Relations Manager, North America
                                 (jay@mysql.com)




Copyright MySQL AB                                  The World’s Most Popular Open Source Database   1
Setup
   ●  The slides use the Sakila sample database
   ●  Download:
   http://downloads.mysql.com/docs/sakila.sql.tar.gz (or.zip)
   ●  The Entity-Relationship diagram is on MySQL Forge:
   http://forge.mysql.com/wiki/Image:SakilaSampleDB-0.8.png
   ●  Install onto your local machine:
          $> tar -xzvf sakila.sql.tar.gz
          $> mysql –user=root –password=xxx < sakila-schema.sql
          $> mysql –user=root –password=xxx < sakila-data.sql




Copyright MySQL AB                          The World’s Most Popular Open Source Database   2
Using EXPLAIN
   ●    Simply append EXPLAIN before any SELECT statement
   ●    Returns a table-ized version of the query execution plan
        chosen by the MySQL query optimizer
   ●    Read the output from top down; each row in the
        EXPLAIN output represents a selection of rows from:
         ➢ A real schema table

         ➢ A “virtual” table (a subquery in the FROM clause)

         ➢ A subquery in the SELECT or WHERE clause

         ➢ A UNIONed resultset




Copyright MySQL AB                          The World’s Most Popular Open Source Database   3
Example EXPLAIN
mysql> EXPLAIN SELECT * FROM rental
    -> INNER JOIN inventory ON rental.inventory_id = inventory.inventory_id
    -> WHERE rental_date BETWEEN '2006-04-01' AND '2006-07-01' G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: rental
         type: range
possible_keys: rental_date,idx_fk_inventory_id
          key: rental_date
      key_len: 8
          ref: NULL
         rows: 1
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: inventory
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 3
          ref: sakila.rental.inventory_id
         rows: 1
        Extra:
2 rows in set (0.00 sec)


Copyright MySQL AB                                 The World’s Most Popular Open Source Database   4
The type Column – Avoid the “ALL”
   ●    Perhaps the most important column in EXPLAIN's output
   ●    Tells you the access strategy which MySQL chose to
        retrieve the specified rows
         ● Watch out for the “ALL” access type!

             ● It means you are doing a full table scan of the

               table's records
             ● Let's see what it looks like...




Copyright MySQL AB                        The World’s Most Popular Open Source Database   5
The ALL access type
mysql> EXPLAIN SELECT * FROM rental G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: rental
         type: ALL          Here, we see that a full table
possible_keys: NULL
          key: NULL         scan is planned. This makes
      key_len: NULL         sense, considering we gave
          ref: NULL         MySQL no WHERE clause by
         rows: 15258
        Extra:
                            which the optimizer could filter the
1 row in set (0.01 sec)     rows or use an index. Also, note
                             the difference between this query,
                             which uses a SELECT * FROM
                             rental, and the next, which selects
                             only the rental_date field...


Copyright MySQL AB                       The World’s Most Popular Open Source Database   6
The type Column – The “index” scan
   ●    The “index” access type is NOT a good thing!
         ● It means you are doing a full index scan of all the

           index' records
         ● Better than a full table scan in most cases, but still

           requires a LOT of resources
         ● Let's see what it looks like...




Copyright MySQL AB                             The World’s Most Popular Open Source Database   7
The index access type
mysql> EXPLAIN SELECT rental_date FROM rental G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: rental
         type: index        Here, we see that a full index
possible_keys: NULL
          key: rental_date scan is planned. By specifying
      key_len: 13           that we only wish to see the
          ref: NULL         rental_date column, we are
         rows: 15258
        Extra: Using index
                            essentially informing the query
1 row in set (0.00 sec)     optimizer that if an index contains
                            the rental_date information, there
                            is no need to pull in the rest of the
                            table fields; instead, the index
                            itself can be used to supply all
                            needed data...

Copyright MySQL AB                       The World’s Most Popular Open Source Database   8
Ahhh, SELECT * ...




       http://img.thedailywtf.com/images/200701/pup2/addedsql.jpg
Copyright MySQL AB                           The World’s Most Popular Open Source Database   9
The type Column – The “range”
   ●    The “range” access type
         ● You have specified a WHERE (or ON) clause that

           uses a range of filters
            ● The BETWEEN operator

            ● The IN() operator

            ● The >, >=, <, <= operators

         ● MySQL has lots of optimizations for range operations,

           which make this access type generally fast
         ● But, you must have an index on the field in question!

         ● Let's see what it looks like...




Copyright MySQL AB                          The World’s Most Popular Open Source Database   10
The range access type
mysql> EXPLAIN SELECT * FROM rental
    -> WHERE rental_date
    -> BETWEEN '2006-01-01' AND '2006-07-01' G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE        Here, we see that a range
        table: rental        access is planned. The
         type: range
possible_keys: rental_date BETWEEN operator means we
          key: rental_date want to access rental records
      key_len: 8             corresponding to a range of rental
          ref: NULL
         rows: 2614
                             dates. Note that the
        Extra: Using where possible_keys column shows us
1 row in set (0.00 sec)      that an index on rental_date is
                            available for the optimizer to use
                            a range access pattern. But what
                            would happen if there weren't an
                            index on rental_date?
Copyright MySQL AB                      The World’s Most Popular Open Source Database   11
YIKES! Back to a full table scan!
mysql> DROP INDEX rental_date ON rental;
Query OK, 16044 rows affected (1.20 sec)
Records: 16044 Duplicates: 0 Warnings: 0

mysql> EXPLAIN SELECT * FROM rental
    -> WHERE rental_date
    -> BETWEEN '2006-01-01' AND '2006-07-01' G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE       Uh oh. Because there is no index
        table: rental
         type: ALL
                            available on the field we are
possible_keys: NULL         filtering by, MySQL cannot use a
          key: NULL         range optimization, and resorts to
      key_len: NULL         the (horrible) full table scan, doing
          ref: NULL
         rows: 16462        a filter on each sequential record
        Extra: Using where to find records meeting our
1 row in set (0.01 sec)     criteria... so indexes are
                             critically important!
Copyright MySQL AB                       The World’s Most Popular Open Source Database   12
The type Column – The “index_merge”
   ●    The “index_merge” access type
         ● New in MySQL 5.0

         ● Optimized data access which can take advantage of

           multiple indexes per query
            ● Prior to MySQL 5.0, only one index can be used

              per table!
         ● Very useful for OR-type queries

         ● Let's see an example...




Copyright MySQL AB                        The World’s Most Popular Open Source Database   13
index_merge example
mysql> EXPLAIN SELECT * FROM rental
    -> WHERE rental_id IN (10,11,12)
    -> OR rental_date = '2006-02-01' G
*************************** 1. row ***************************
            id: 1
  select_type: SIMPLE
        table: rental
         type: index_merge
possible_keys: PRIMARY,rental_date
          key: rental_date,PRIMARY
      key_len: 8,4
          ref: NULL
         rows: 4
        Extra: Using sort_union(rental_date,PRIMARY);
Using where
      There are two indexes available to the MySQL optimizer
1 row in set (0.04 sec)

      which can help it filter records. Prior to MySQL 5.0, the
      optimizer would have to choose which index would filter the
      most records for query...
Copyright MySQL AB                         The World’s Most Popular Open Source Database   14
Index Merge (cont'd)
   ●    Can be any of:
         ● sort_union

            ● Previous example. OR conditions with ranges on

              non-primary key fields
         ● union

            ● OR conditions using constants or ranges on

              primary key fields (and table is InnoDB)
         ● intersection

            ● AND conditions with constants or range conditions

              on primary key fields (and table is InnoDB)
   ●    No FULLTEXT support (but planned!)


Copyright MySQL AB                         The World’s Most Popular Open Source Database   15
The ref access type
   ●    A performance benefit when the number of returned
        rows is relatively small
   ●    When you supply MySQL with a constant value on an
        indexed field (example ahead)
   ●    Or, when you are accessing a joined table through the
        joining table's indexed field (example ahead)
   ●    Very, very fast retrieval through the index seek or single
        sweep multi-join




Copyright MySQL AB                            The World’s Most Popular Open Source Database   16
ref access type example (on indexed field)
mysql> EXPLAIN SELECT * FROM rental
    -> WHERE rental_id IN (10,11,12)
    -> AND rental_date = '2006-02-01' G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: rental
         type: ref
possible_keys: PRIMARY,rental_date
          key: rental_date
      key_len: 8
          ref: const
         rows: 1
        Extra: Using where
      Again, there are two indexes available to the MySQL
1 row in set (0.01 sec)

      optimizer which can help it filter records here. But, the
      optimizer decides the best access strategy is to seek into
      the rental_date index and find the appropriate record(s) and
      then filter that result based on the IN() expression
Copyright MySQL AB                          The World’s Most Popular Open Source Database   17
ref access type example (on join)
mysql> EXPLAIN SELECT * FROM rental
    -> INNER JOIN inventory ON inventory.inventory_id=rental.inventory_id G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE                            Here, an example of
        table: inventory
         type: ALL
                                                 the ref access type
possible_keys: PRIMARY                           when the outer table
          key: NULL
      key_len: NULL                              (inventory) is joined to
          ref: NULL
         rows: 5007
                                                 the rental table on an
        Extra:                                   indexed field. Note that
                                                 even though we
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: rental
                                                 entered the rental table
         type: ref                               first in the FROM
                                                 clause, the inventory
possible_keys: idx_fk_inventory_id
          key: idx_fk_inventory_id
      key_len: 3
          ref: sakila.inventory.inventory_id
                                                 table was chosen as
         rows: 1                                 the first table to access.
                                                 Why? Because it has
        Extra:
2 rows in set (0.00 sec)
                                                 fewer rows...
Copyright MySQL AB                                 The World’s Most Popular Open Source Database   18
The eq_ref access type
   ●    Performance nerdvana
   ●    Applies to situations where the joined column is a
        primary or unique index
   ●    Über-performance because optimizations are made to
        quickly locate the single record which will meet the join
        condition
   ●    Let's see...




Copyright MySQL AB                            The World’s Most Popular Open Source Database   19
eq_ref access type example
mysql> EXPLAIN SELECT f.film_id, f.title, c.name
     > FROM film f INNER JOIN film_category fc
     > ON f.film_id=fc.film_id INNER JOIN category c
     > ON fc.category_id=c.category_id WHERE f.title LIKE 'T%' G
*************************** 1. row ***************************
  select_type: SIMPLE
        table: c
         type: ALL
possible_keys: PRIMARY
                                                   Note that the third row shows the
          key: NULL                                eq_ref access. Even though there
                                                   was an index available which could
      key_len: NULL
          ref: NULL
         rows: 16
        Extra:                                     be used (we do a WHERE on the
                                                   film.title field, which has an index on
*************************** 2. row ***************************
  select_type: SIMPLE
        table: fc                                  it), the optimizer chooses to use the
         type: ref
possible_keys: PRIMARY,fk_film_category_category   PRIMARY key to fulfill the select
          key: fk_film_category_category
      key_len: 1                                   request. Why? It viewed the 16
          ref: sakila.c.category_id
         rows: 1
                                                   rows in the category table and
        Extra: Using index                         decided that the quickest way to
*************************** 3. row ***************************
  select_type: SIMPLE                              access the data through the join
        table: f
         type: eq_ref                              fields in the film_category table.
possible_keys: PRIMARY,idx_title
          key: PRIMARY
                                                   These 16 rows is less than the 46
      key_len: 2
          ref: sakila.fc.film_id
                                                   rows returned from the title index
         rows: 1                                   which match the query filter
        Extra: Using where

Copyright MySQL AB                                                  The World’s Most Popular Open Source Database   20
The importance of isolating indexed fields
mysql> EXPLAIN SELECT * FROM film WHERE title LIKE 'Tr%'G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film                      Nice. In the top query, we have a
         type: range
possible_keys: idx_title
                                         fast range access on the indexed
          key: idx_title                 field
      key_len: 767
          ref: NULL
         rows: 15
        Extra: Using where

mysql> EXPLAIN SELECT * FROM film WHERE LEFT(title,2) = 'Tr' G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film                      Oops. In the bottom query, we
         type: ALL
possible_keys: NULL                      have a slower full table scan
          key: NULL                      because of the function
      key_len: NULL
          ref: NULL
                                         operating on the indexed field
         rows: 951                       (the LEFT() function)
        Extra: Using where

Copyright MySQL AB                              The World’s Most Popular Open Source Database   21
index_subquery and unique_subquery
   ●    Appear when you use subqueries in your SELECT
        statement
   ●    Subqueries yielding a unique set of data will produce
        unique_subquery, otherwise index_subquery
         ● unique_subquery is slightly better performing

           because the optimizer can entirely replace the
           subquery with a set of constants
             ● So it becomes a range condition


   ●    Generally, a join will be better performing though...
   ●    Let's see it in action




Copyright MySQL AB                          The World’s Most Popular Open Source Database   22
unique_subery access type example
mysql> EXPLAIN SELECT * FROM rental r
    -> WHERE r.customer_id IN (           The outer table (rental) is accessed
    -> SELECT customer_id FROM customer
    -> WHERE last_name LIKE 'S%') G      via a full table scan, and for each
*************************** 1. row *************************** a WHERE filter
                                          record in the table,
           id: 1
  select_type: PRIMARY
                                          is applied against a set of constant
        table: r                          customer_id values determined
         type: ALL                        from the unique_subquery result in
possible_keys: NULL
          key: NULL                       the bottom select.
      key_len: NULL
          ref: NULL
         rows: 15646
                                          Note that the select_type shows
        Extra: Using where                DEPENDENT SUBQUERY. This is
*************************** 2. row *************************** as the
                                          technically incorrect,
           id: 2
  select_type: DEPENDENT SUBQUERY         subquery is not a correlated
        table: customer                   subquery, but rather returns a list of
         type: unique_subquery
possible_keys: PRIMARY,idx_last_name
                                          constants...
          key: PRIMARY
      key_len: 2                          Also, the strategy doesn't take
          ref: func
         rows: 1                          advantage of the index on
        Extra: Using index; Using where customer.last_name...

Copyright MySQL AB                                  The World’s Most Popular Open Source Database   23
Rewriting the subquery as a standard join
mysql> EXPLAIN SELECT * FROM rental r
    -> INNER JOIN customer c                      The standard join gives an
    -> ON r.customer_id=c.customer_id
    -> WHERE last_name LIKE 'S%' G               entirely different query
                                                  execution plan (and a faster
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
                                                  one) even though the
        table: c                                  results of the query are
         type: range                              identical.
possible_keys: PRIMARY,idx_last_name
          key: idx_last_name
      key_len: 137                                Suggestion:
          ref: NULL
         rows: 54
        Extra: Using where                        Rewrite subqueries
*************************** 2. row *************************** correlated
                                                  (especially
           id: 1
  select_type: SIMPLE                             subqueries) into standard
        table: r                                  joins
         type: ref
possible_keys: idx_fk_customer_id
          key: idx_fk_customer_id
      key_len: 2
          ref: sakila.c.customer_id
         rows: 13
        Extra:

Copyright MySQL AB                                The World’s Most Popular Open Source Database   24
The select_type Column
●   select_type is mostly just informative, but watch for the
    following:
     ● DEPENDENT SUBQUERY

         ● Means you've used a correlated subquery

         ● But can show non-correlated subqueries as dependent...

         ● Ensure there isn't a more efficient way of joining the

           information
     ● UNCACHEABLE SUBQUERY

         ● Similar to DEPENDENT SUBQUERY, but means that for

           each matched row in the outer query, the subquery must
           be re-evaluated
         ● For instance, if you use a user variable (@my_var) in

           your subquery
Copyright MySQL AB                        The World’s Most Popular Open Source Database   25
Effects of GROUP BY and ORDER BY
●   GROUP BY and ORDER BY:
    ● Will produce “Using filesort” and/or “Using temporary” in the

      Extra column only when an index cannot be used for the
      grouping/sorting
    ● Let's see the difference between group by selects on

      indexed vs. non-indexed fields...




Copyright MySQL AB                         The World’s Most Popular Open Source Database   26
Effects of GROUP BY and ORDER BY
mysql> EXPLAIN SELECT r.staff_id, COUNT(*)
    -> FROM rental r GROUP BY r.staff_id G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: r
         type: index                                    The top query, since
possible_keys: NULL                                     it groups on an
          key: idx_fk_staff_id
      key_len: 1
                                                        indexed field, does
          ref: NULL                                     not require a filesort
         rows: 15646                                    and temporary
        Extra: Using index
                                                        storage to do the
mysql> EXPLAIN SELECT r.return_date, COUNT(*)           sort/group that the
    -> FROM rental r GROUP BY r.return_date G          bottom query does,
*************************** 1. row ***************************
           id: 1                                        which groups on a
  select_type: SIMPLE                                   non-indexed field.
        table:       r
         type:       ALL
possible_keys:       NULL
          key:       NULL
      key_len:       NULL
          ref:       NULL
         rows:       15646
        Extra:       Using temporary; Using filesort
Copyright MySQL AB                                     The World’s Most Popular Open Source Database   27
Views
●   Evaluated into an underlying SELECT statement
●   WHERE expression can be applied on the view, which is then
    translated into a WHERE expression on the underlying table(s)
●   But, what does the EXPLAIN return for a view? and...
●   Does it differ from an EXPLAIN on an identical SELECT the
    underlying tables?
●   Let's see...




Copyright MySQL AB                        The World’s Most Popular Open Source Database   28
The sales_by_film_category view
CREATE VIEW sales_by_film_category
AS
SELECT
c.name AS category
, SUM(p.amount) AS total_sales
FROM payment AS p
INNER JOIN rental AS r ON p.rental_id = r.rental_id
INNER JOIN inventory AS i ON r.inventory_id = i.inventory_id
INNER JOIN film AS f ON i.film_id = f.film_id
INNER JOIN film_category AS fc ON f.film_id = fc.film_id
INNER JOIN category AS c ON fc.category_id = c.category_id
GROUP BY c.name
ORDER BY total_sales DESC;
                The view joins a number of tables together to make it easier and
                less cumbersome to query for the information above. Instead of
                executing the above statement, you would execute SELECT *
                FROM sales_by_film_category;



Copyright MySQL AB                                    The World’s Most Popular Open Source Database   29
EXPLAIN on a view
mysql> EXPLAIN SELECT * FROM sales_by_film_category;
+----+-------------+------------+--------+---------------------------------+
| id | select_type | table      | type   | Extra                           |
+----+-------------+------------+--------+---------------------------------+
| 1 | PRIMARY      | <derived2> | ALL    |                                 |
| 2 | DERIVED      | c          | ALL    | Using temporary; Using filesort |
| 2 | DERIVED      | fc         | ref    | Using index                     |
| 2 | DERIVED      | f          | eq_ref | Using index                     |
| 2 | DERIVED      | i          | ref    | Using index                     |
| 2 | DERIVED      | r          | ref    | Using index                     |
| 2 | DERIVED      | p          | ref    | Using where                     |
+----+-------------+------------+--------+---------------------------------+
7 rows in set (0.22 sec)

         I've abbreviated the output from above for brevity, but notice the
         plethora (yes, plethora) of DERIVED select types? Did you notice
         any derived tables (subqueries in the FROM clause) in the original
         view definition? Nope. This is because of the internal rewrite that
         occurs; the underlying select is turned into a set of derived
         subqueries that can be independently filtered using a WHERE
         expression. What happens if we remove the SELECT * and replace
         with a SELECT category? Will the EXPLAIN output change?

Copyright MySQL AB                                 The World’s Most Popular Open Source Database   30
EXPLAIN on a view with specified column
mysql> EXPLAIN SELECT category FROM sales_by_film_category;
+----+-------------+------------+--------+---------------------------------+
| id | select_type | table      | type   | Extra                           |
+----+-------------+------------+--------+---------------------------------+
| 1 | PRIMARY      | <derived2> | ALL    |                                 |
| 2 | DERIVED      | c          | ALL    | Using temporary; Using filesort |
| 2 | DERIVED      | fc         | ref    | Using index                     |
| 2 | DERIVED      | f          | eq_ref | Using index                     |
| 2 | DERIVED      | i          | ref    | Using index                     |
| 2 | DERIVED      | r          | ref    | Using index                     |
| 2 | DERIVED      | p          | ref    | Using where                     |
+----+-------------+------------+--------+---------------------------------+
7 rows in set (0.25 sec)

         As you can see, there is no change at all in the EXPLAIN output,
         because of the underlying rewrite happening, there are fewer
         optimizations that we can use with views.

         In general, views will perform worse than an identical SELECT on
         the underlying tables. However, depending on your situation, the
         ease of using the view may be worth the performance impact.


Copyright MySQL AB                                 The World’s Most Popular Open Source Database   31
Closing Arguments
●   EXPLAIN EXTENDED
     ● Gives more information on the query execution plan

       produced for more complex queries. Issue EXPLAIN
       EXTENDED SELECT ..., and then SHOW WARNINGS;
●   SHOW PROFILE
     ● Patch committed by Jeremy Cole will be going into the

       MySQL 5.0.35 Community Server, to be released shortly
     ● Provides fine-tuned profiling information on disk I/O and

       various internal state changes during query parsing and
       execution. Check out:
     http://jcole.us/blog/archives/category/mysql/



Copyright MySQL AB                         The World’s Most Popular Open Source Database   32
MySQL Conference & Expo 2007
          April 23-26, Santa Clara, California

                     Over 100 Sessions & Tutorials
                      • Performance Tuning & Benchmarks
                      • Clustering, Replication, & Scale-Out
                      • Data Warehousing, Reporting & BI
                      • Security & Administration
                      • PHP, LAMP, & MySQL
                      • Web 2.0, Ajax, Ruby
                      • And Much More…



http://www.mysqlconf.com

More Related Content

What's hot

Scaling MySQL Strategies for Developers
Scaling MySQL Strategies for DevelopersScaling MySQL Strategies for Developers
Scaling MySQL Strategies for DevelopersJonathan Levin
 
Optimizing queries MySQL
Optimizing queries MySQLOptimizing queries MySQL
Optimizing queries MySQLGeorgi Sotirov
 
0888 learning-mysql
0888 learning-mysql0888 learning-mysql
0888 learning-mysqlsabir18
 
Optimizer Histograms: When they Help and When Do Not?
Optimizer Histograms: When they Help and When Do Not?Optimizer Histograms: When they Help and When Do Not?
Optimizer Histograms: When they Help and When Do Not?Sveta Smirnova
 
Preparse Query Rewrite Plugins
Preparse Query Rewrite PluginsPreparse Query Rewrite Plugins
Preparse Query Rewrite PluginsSveta Smirnova
 
Understanding Query Execution
Understanding Query ExecutionUnderstanding Query Execution
Understanding Query Executionwebhostingguy
 
Powerful Explain in MySQL 5.6
Powerful Explain in MySQL 5.6Powerful Explain in MySQL 5.6
Powerful Explain in MySQL 5.6MYXPLAIN
 
Introduction into MySQL Query Tuning for Dev[Op]s
Introduction into MySQL Query Tuning for Dev[Op]sIntroduction into MySQL Query Tuning for Dev[Op]s
Introduction into MySQL Query Tuning for Dev[Op]sSveta Smirnova
 
Introduction to MySQL Query Tuning for Dev[Op]s
Introduction to MySQL Query Tuning for Dev[Op]sIntroduction to MySQL Query Tuning for Dev[Op]s
Introduction to MySQL Query Tuning for Dev[Op]sSveta Smirnova
 
Billion Goods in Few Categories: how Histograms Save a Life?
Billion Goods in Few Categories: how Histograms Save a Life?Billion Goods in Few Categories: how Histograms Save a Life?
Billion Goods in Few Categories: how Histograms Save a Life?Sveta Smirnova
 
Introduction into MySQL Query Tuning
Introduction into MySQL Query TuningIntroduction into MySQL Query Tuning
Introduction into MySQL Query TuningSveta Smirnova
 
MySQL partitions tutorial
MySQL partitions tutorialMySQL partitions tutorial
MySQL partitions tutorialGiuseppe Maxia
 
A Billion Goods in a Few Categories: When Optimizer Histograms Help and When ...
A Billion Goods in a Few Categories: When Optimizer Histograms Help and When ...A Billion Goods in a Few Categories: When Optimizer Histograms Help and When ...
A Billion Goods in a Few Categories: When Optimizer Histograms Help and When ...Sveta Smirnova
 
Modern solutions for modern database load: improvements in the latest MariaDB...
Modern solutions for modern database load: improvements in the latest MariaDB...Modern solutions for modern database load: improvements in the latest MariaDB...
Modern solutions for modern database load: improvements in the latest MariaDB...Sveta Smirnova
 
Billion Goods in Few Categories: How Histograms Save a Life?
Billion Goods in Few Categories: How Histograms Save a Life?Billion Goods in Few Categories: How Histograms Save a Life?
Billion Goods in Few Categories: How Histograms Save a Life?Sveta Smirnova
 

What's hot (20)

Scaling MySQL Strategies for Developers
Scaling MySQL Strategies for DevelopersScaling MySQL Strategies for Developers
Scaling MySQL Strategies for Developers
 
Load Data Fast!
Load Data Fast!Load Data Fast!
Load Data Fast!
 
Optimizing queries MySQL
Optimizing queries MySQLOptimizing queries MySQL
Optimizing queries MySQL
 
0888 learning-mysql
0888 learning-mysql0888 learning-mysql
0888 learning-mysql
 
Optimizer Histograms: When they Help and When Do Not?
Optimizer Histograms: When they Help and When Do Not?Optimizer Histograms: When they Help and When Do Not?
Optimizer Histograms: When they Help and When Do Not?
 
Percona toolkit
Percona toolkitPercona toolkit
Percona toolkit
 
Preparse Query Rewrite Plugins
Preparse Query Rewrite PluginsPreparse Query Rewrite Plugins
Preparse Query Rewrite Plugins
 
Understanding Query Execution
Understanding Query ExecutionUnderstanding Query Execution
Understanding Query Execution
 
Powerful Explain in MySQL 5.6
Powerful Explain in MySQL 5.6Powerful Explain in MySQL 5.6
Powerful Explain in MySQL 5.6
 
Introduction into MySQL Query Tuning for Dev[Op]s
Introduction into MySQL Query Tuning for Dev[Op]sIntroduction into MySQL Query Tuning for Dev[Op]s
Introduction into MySQL Query Tuning for Dev[Op]s
 
How to Use JSON in MySQL Wrong
How to Use JSON in MySQL WrongHow to Use JSON in MySQL Wrong
How to Use JSON in MySQL Wrong
 
Introduction to MySQL Query Tuning for Dev[Op]s
Introduction to MySQL Query Tuning for Dev[Op]sIntroduction to MySQL Query Tuning for Dev[Op]s
Introduction to MySQL Query Tuning for Dev[Op]s
 
Billion Goods in Few Categories: how Histograms Save a Life?
Billion Goods in Few Categories: how Histograms Save a Life?Billion Goods in Few Categories: how Histograms Save a Life?
Billion Goods in Few Categories: how Histograms Save a Life?
 
Introduction into MySQL Query Tuning
Introduction into MySQL Query TuningIntroduction into MySQL Query Tuning
Introduction into MySQL Query Tuning
 
Sql query patterns, optimized
Sql query patterns, optimizedSql query patterns, optimized
Sql query patterns, optimized
 
MySQL partitions tutorial
MySQL partitions tutorialMySQL partitions tutorial
MySQL partitions tutorial
 
A Billion Goods in a Few Categories: When Optimizer Histograms Help and When ...
A Billion Goods in a Few Categories: When Optimizer Histograms Help and When ...A Billion Goods in a Few Categories: When Optimizer Histograms Help and When ...
A Billion Goods in a Few Categories: When Optimizer Histograms Help and When ...
 
Schemadoc
SchemadocSchemadoc
Schemadoc
 
Modern solutions for modern database load: improvements in the latest MariaDB...
Modern solutions for modern database load: improvements in the latest MariaDB...Modern solutions for modern database load: improvements in the latest MariaDB...
Modern solutions for modern database load: improvements in the latest MariaDB...
 
Billion Goods in Few Categories: How Histograms Save a Life?
Billion Goods in Few Categories: How Histograms Save a Life?Billion Goods in Few Categories: How Histograms Save a Life?
Billion Goods in Few Categories: How Histograms Save a Life?
 

Similar to Understanding Query Execution Plans

MySQL 8.0 New Features -- September 27th presentation for Open Source Summit
MySQL 8.0 New Features -- September 27th presentation for Open Source SummitMySQL 8.0 New Features -- September 27th presentation for Open Source Summit
MySQL 8.0 New Features -- September 27th presentation for Open Source SummitDave Stokes
 
My sql technical reference manual
My sql technical reference manualMy sql technical reference manual
My sql technical reference manualMir Majid
 
MySQL Indexing : Improving Query Performance Using Index (Covering Index)
MySQL Indexing : Improving Query Performance Using Index (Covering Index)MySQL Indexing : Improving Query Performance Using Index (Covering Index)
MySQL Indexing : Improving Query Performance Using Index (Covering Index)Hemant Kumar Singh
 
MySQL 8 -- A new beginning : Sunshine PHP/PHP UK (updated)
MySQL 8 -- A new beginning : Sunshine PHP/PHP UK (updated)MySQL 8 -- A new beginning : Sunshine PHP/PHP UK (updated)
MySQL 8 -- A new beginning : Sunshine PHP/PHP UK (updated)Dave Stokes
 
15 Ways to Kill Your Mysql Application Performance
15 Ways to Kill Your Mysql Application Performance15 Ways to Kill Your Mysql Application Performance
15 Ways to Kill Your Mysql Application Performanceguest9912e5
 
Linuxfest Northwest 2022 - MySQL 8.0 Nre Features
Linuxfest Northwest 2022 - MySQL 8.0 Nre FeaturesLinuxfest Northwest 2022 - MySQL 8.0 Nre Features
Linuxfest Northwest 2022 - MySQL 8.0 Nre FeaturesDave Stokes
 
Advanced MySQL Query Optimizations
Advanced MySQL Query OptimizationsAdvanced MySQL Query Optimizations
Advanced MySQL Query OptimizationsDave Stokes
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak SearchJustin Edelson
 
MySQL Performance Optimization
MySQL Performance OptimizationMySQL Performance Optimization
MySQL Performance OptimizationMindfire Solutions
 
mysqlanditsbasiccommands-150226033905-conversion-gate02.pdf
mysqlanditsbasiccommands-150226033905-conversion-gate02.pdfmysqlanditsbasiccommands-150226033905-conversion-gate02.pdf
mysqlanditsbasiccommands-150226033905-conversion-gate02.pdfpradnyamulay
 
MySQL Reference Manual
MySQL Reference ManualMySQL Reference Manual
MySQL Reference Manualwebhostingguy
 
Why Use EXPLAIN FORMAT=JSON?
 Why Use EXPLAIN FORMAT=JSON?  Why Use EXPLAIN FORMAT=JSON?
Why Use EXPLAIN FORMAT=JSON? Sveta Smirnova
 
android sqlite
android sqliteandroid sqlite
android sqliteDeepa Rani
 
SQL PPT.pptx
SQL PPT.pptxSQL PPT.pptx
SQL PPT.pptxKulbir4
 
Database Performance Tuning
Database Performance Tuning Database Performance Tuning
Database Performance Tuning Arno Huetter
 
PHP UK 2020 Tutorial: MySQL Indexes, Histograms And other ways To Speed Up Yo...
PHP UK 2020 Tutorial: MySQL Indexes, Histograms And other ways To Speed Up Yo...PHP UK 2020 Tutorial: MySQL Indexes, Histograms And other ways To Speed Up Yo...
PHP UK 2020 Tutorial: MySQL Indexes, Histograms And other ways To Speed Up Yo...Dave Stokes
 

Similar to Understanding Query Execution Plans (20)

MySQL 8.0 New Features -- September 27th presentation for Open Source Summit
MySQL 8.0 New Features -- September 27th presentation for Open Source SummitMySQL 8.0 New Features -- September 27th presentation for Open Source Summit
MySQL 8.0 New Features -- September 27th presentation for Open Source Summit
 
My sql technical reference manual
My sql technical reference manualMy sql technical reference manual
My sql technical reference manual
 
MySQL Indexing : Improving Query Performance Using Index (Covering Index)
MySQL Indexing : Improving Query Performance Using Index (Covering Index)MySQL Indexing : Improving Query Performance Using Index (Covering Index)
MySQL Indexing : Improving Query Performance Using Index (Covering Index)
 
MySQL 8 -- A new beginning : Sunshine PHP/PHP UK (updated)
MySQL 8 -- A new beginning : Sunshine PHP/PHP UK (updated)MySQL 8 -- A new beginning : Sunshine PHP/PHP UK (updated)
MySQL 8 -- A new beginning : Sunshine PHP/PHP UK (updated)
 
15 Ways to Kill Your Mysql Application Performance
15 Ways to Kill Your Mysql Application Performance15 Ways to Kill Your Mysql Application Performance
15 Ways to Kill Your Mysql Application Performance
 
Linuxfest Northwest 2022 - MySQL 8.0 Nre Features
Linuxfest Northwest 2022 - MySQL 8.0 Nre FeaturesLinuxfest Northwest 2022 - MySQL 8.0 Nre Features
Linuxfest Northwest 2022 - MySQL 8.0 Nre Features
 
Advanced MySQL Query Optimizations
Advanced MySQL Query OptimizationsAdvanced MySQL Query Optimizations
Advanced MySQL Query Optimizations
 
Demystifying Oak Search
Demystifying Oak SearchDemystifying Oak Search
Demystifying Oak Search
 
EVOLVE'14 | Enhance | Justin Edelson & Darin Kuntze | Demystifying Oak Search
EVOLVE'14 | Enhance | Justin Edelson & Darin Kuntze | Demystifying Oak SearchEVOLVE'14 | Enhance | Justin Edelson & Darin Kuntze | Demystifying Oak Search
EVOLVE'14 | Enhance | Justin Edelson & Darin Kuntze | Demystifying Oak Search
 
MySQL Performance Optimization
MySQL Performance OptimizationMySQL Performance Optimization
MySQL Performance Optimization
 
MySQL and its basic commands
MySQL and its basic commandsMySQL and its basic commands
MySQL and its basic commands
 
Oracle notes
Oracle notesOracle notes
Oracle notes
 
mysqlanditsbasiccommands-150226033905-conversion-gate02.pdf
mysqlanditsbasiccommands-150226033905-conversion-gate02.pdfmysqlanditsbasiccommands-150226033905-conversion-gate02.pdf
mysqlanditsbasiccommands-150226033905-conversion-gate02.pdf
 
MySQL Reference Manual
MySQL Reference ManualMySQL Reference Manual
MySQL Reference Manual
 
Why Use EXPLAIN FORMAT=JSON?
 Why Use EXPLAIN FORMAT=JSON?  Why Use EXPLAIN FORMAT=JSON?
Why Use EXPLAIN FORMAT=JSON?
 
android sqlite
android sqliteandroid sqlite
android sqlite
 
SQL PPT.pptx
SQL PPT.pptxSQL PPT.pptx
SQL PPT.pptx
 
Database Performance Tuning
Database Performance Tuning Database Performance Tuning
Database Performance Tuning
 
Performance Tuning
Performance TuningPerformance Tuning
Performance Tuning
 
PHP UK 2020 Tutorial: MySQL Indexes, Histograms And other ways To Speed Up Yo...
PHP UK 2020 Tutorial: MySQL Indexes, Histograms And other ways To Speed Up Yo...PHP UK 2020 Tutorial: MySQL Indexes, Histograms And other ways To Speed Up Yo...
PHP UK 2020 Tutorial: MySQL Indexes, Histograms And other ways To Speed Up Yo...
 

Understanding Query Execution Plans

  • 1. Understanding Query Execution Jay Pipes Community Relations Manager, North America (jay@mysql.com) Copyright MySQL AB The World’s Most Popular Open Source Database 1
  • 2. Setup ● The slides use the Sakila sample database ● Download: http://downloads.mysql.com/docs/sakila.sql.tar.gz (or.zip) ● The Entity-Relationship diagram is on MySQL Forge: http://forge.mysql.com/wiki/Image:SakilaSampleDB-0.8.png ● Install onto your local machine: $> tar -xzvf sakila.sql.tar.gz $> mysql –user=root –password=xxx < sakila-schema.sql $> mysql –user=root –password=xxx < sakila-data.sql Copyright MySQL AB The World’s Most Popular Open Source Database 2
  • 3. Using EXPLAIN ● Simply append EXPLAIN before any SELECT statement ● Returns a table-ized version of the query execution plan chosen by the MySQL query optimizer ● Read the output from top down; each row in the EXPLAIN output represents a selection of rows from: ➢ A real schema table ➢ A “virtual” table (a subquery in the FROM clause) ➢ A subquery in the SELECT or WHERE clause ➢ A UNIONed resultset Copyright MySQL AB The World’s Most Popular Open Source Database 3
  • 4. Example EXPLAIN mysql> EXPLAIN SELECT * FROM rental -> INNER JOIN inventory ON rental.inventory_id = inventory.inventory_id -> WHERE rental_date BETWEEN '2006-04-01' AND '2006-07-01' G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental type: range possible_keys: rental_date,idx_fk_inventory_id key: rental_date key_len: 8 ref: NULL rows: 1 Extra: Using where *************************** 2. row *************************** id: 1 select_type: SIMPLE table: inventory type: eq_ref possible_keys: PRIMARY key: PRIMARY key_len: 3 ref: sakila.rental.inventory_id rows: 1 Extra: 2 rows in set (0.00 sec) Copyright MySQL AB The World’s Most Popular Open Source Database 4
  • 5. The type Column – Avoid the “ALL” ● Perhaps the most important column in EXPLAIN's output ● Tells you the access strategy which MySQL chose to retrieve the specified rows ● Watch out for the “ALL” access type! ● It means you are doing a full table scan of the table's records ● Let's see what it looks like... Copyright MySQL AB The World’s Most Popular Open Source Database 5
  • 6. The ALL access type mysql> EXPLAIN SELECT * FROM rental G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental type: ALL Here, we see that a full table possible_keys: NULL key: NULL scan is planned. This makes key_len: NULL sense, considering we gave ref: NULL MySQL no WHERE clause by rows: 15258 Extra: which the optimizer could filter the 1 row in set (0.01 sec) rows or use an index. Also, note the difference between this query, which uses a SELECT * FROM rental, and the next, which selects only the rental_date field... Copyright MySQL AB The World’s Most Popular Open Source Database 6
  • 7. The type Column – The “index” scan ● The “index” access type is NOT a good thing! ● It means you are doing a full index scan of all the index' records ● Better than a full table scan in most cases, but still requires a LOT of resources ● Let's see what it looks like... Copyright MySQL AB The World’s Most Popular Open Source Database 7
  • 8. The index access type mysql> EXPLAIN SELECT rental_date FROM rental G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental type: index Here, we see that a full index possible_keys: NULL key: rental_date scan is planned. By specifying key_len: 13 that we only wish to see the ref: NULL rental_date column, we are rows: 15258 Extra: Using index essentially informing the query 1 row in set (0.00 sec) optimizer that if an index contains the rental_date information, there is no need to pull in the rest of the table fields; instead, the index itself can be used to supply all needed data... Copyright MySQL AB The World’s Most Popular Open Source Database 8
  • 9. Ahhh, SELECT * ... http://img.thedailywtf.com/images/200701/pup2/addedsql.jpg Copyright MySQL AB The World’s Most Popular Open Source Database 9
  • 10. The type Column – The “range” ● The “range” access type ● You have specified a WHERE (or ON) clause that uses a range of filters ● The BETWEEN operator ● The IN() operator ● The >, >=, <, <= operators ● MySQL has lots of optimizations for range operations, which make this access type generally fast ● But, you must have an index on the field in question! ● Let's see what it looks like... Copyright MySQL AB The World’s Most Popular Open Source Database 10
  • 11. The range access type mysql> EXPLAIN SELECT * FROM rental -> WHERE rental_date -> BETWEEN '2006-01-01' AND '2006-07-01' G *************************** 1. row *************************** id: 1 select_type: SIMPLE Here, we see that a range table: rental access is planned. The type: range possible_keys: rental_date BETWEEN operator means we key: rental_date want to access rental records key_len: 8 corresponding to a range of rental ref: NULL rows: 2614 dates. Note that the Extra: Using where possible_keys column shows us 1 row in set (0.00 sec) that an index on rental_date is available for the optimizer to use a range access pattern. But what would happen if there weren't an index on rental_date? Copyright MySQL AB The World’s Most Popular Open Source Database 11
  • 12. YIKES! Back to a full table scan! mysql> DROP INDEX rental_date ON rental; Query OK, 16044 rows affected (1.20 sec) Records: 16044 Duplicates: 0 Warnings: 0 mysql> EXPLAIN SELECT * FROM rental -> WHERE rental_date -> BETWEEN '2006-01-01' AND '2006-07-01' G *************************** 1. row *************************** id: 1 select_type: SIMPLE Uh oh. Because there is no index table: rental type: ALL available on the field we are possible_keys: NULL filtering by, MySQL cannot use a key: NULL range optimization, and resorts to key_len: NULL the (horrible) full table scan, doing ref: NULL rows: 16462 a filter on each sequential record Extra: Using where to find records meeting our 1 row in set (0.01 sec) criteria... so indexes are critically important! Copyright MySQL AB The World’s Most Popular Open Source Database 12
  • 13. The type Column – The “index_merge” ● The “index_merge” access type ● New in MySQL 5.0 ● Optimized data access which can take advantage of multiple indexes per query ● Prior to MySQL 5.0, only one index can be used per table! ● Very useful for OR-type queries ● Let's see an example... Copyright MySQL AB The World’s Most Popular Open Source Database 13
  • 14. index_merge example mysql> EXPLAIN SELECT * FROM rental -> WHERE rental_id IN (10,11,12) -> OR rental_date = '2006-02-01' G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental type: index_merge possible_keys: PRIMARY,rental_date key: rental_date,PRIMARY key_len: 8,4 ref: NULL rows: 4 Extra: Using sort_union(rental_date,PRIMARY); Using where There are two indexes available to the MySQL optimizer 1 row in set (0.04 sec) which can help it filter records. Prior to MySQL 5.0, the optimizer would have to choose which index would filter the most records for query... Copyright MySQL AB The World’s Most Popular Open Source Database 14
  • 15. Index Merge (cont'd) ● Can be any of: ● sort_union ● Previous example. OR conditions with ranges on non-primary key fields ● union ● OR conditions using constants or ranges on primary key fields (and table is InnoDB) ● intersection ● AND conditions with constants or range conditions on primary key fields (and table is InnoDB) ● No FULLTEXT support (but planned!) Copyright MySQL AB The World’s Most Popular Open Source Database 15
  • 16. The ref access type ● A performance benefit when the number of returned rows is relatively small ● When you supply MySQL with a constant value on an indexed field (example ahead) ● Or, when you are accessing a joined table through the joining table's indexed field (example ahead) ● Very, very fast retrieval through the index seek or single sweep multi-join Copyright MySQL AB The World’s Most Popular Open Source Database 16
  • 17. ref access type example (on indexed field) mysql> EXPLAIN SELECT * FROM rental -> WHERE rental_id IN (10,11,12) -> AND rental_date = '2006-02-01' G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: rental type: ref possible_keys: PRIMARY,rental_date key: rental_date key_len: 8 ref: const rows: 1 Extra: Using where Again, there are two indexes available to the MySQL 1 row in set (0.01 sec) optimizer which can help it filter records here. But, the optimizer decides the best access strategy is to seek into the rental_date index and find the appropriate record(s) and then filter that result based on the IN() expression Copyright MySQL AB The World’s Most Popular Open Source Database 17
  • 18. ref access type example (on join) mysql> EXPLAIN SELECT * FROM rental -> INNER JOIN inventory ON inventory.inventory_id=rental.inventory_id G *************************** 1. row *************************** id: 1 select_type: SIMPLE Here, an example of table: inventory type: ALL the ref access type possible_keys: PRIMARY when the outer table key: NULL key_len: NULL (inventory) is joined to ref: NULL rows: 5007 the rental table on an Extra: indexed field. Note that even though we *************************** 2. row *************************** id: 1 select_type: SIMPLE table: rental entered the rental table type: ref first in the FROM clause, the inventory possible_keys: idx_fk_inventory_id key: idx_fk_inventory_id key_len: 3 ref: sakila.inventory.inventory_id table was chosen as rows: 1 the first table to access. Why? Because it has Extra: 2 rows in set (0.00 sec) fewer rows... Copyright MySQL AB The World’s Most Popular Open Source Database 18
  • 19. The eq_ref access type ● Performance nerdvana ● Applies to situations where the joined column is a primary or unique index ● Über-performance because optimizations are made to quickly locate the single record which will meet the join condition ● Let's see... Copyright MySQL AB The World’s Most Popular Open Source Database 19
  • 20. eq_ref access type example mysql> EXPLAIN SELECT f.film_id, f.title, c.name > FROM film f INNER JOIN film_category fc > ON f.film_id=fc.film_id INNER JOIN category c > ON fc.category_id=c.category_id WHERE f.title LIKE 'T%' G *************************** 1. row *************************** select_type: SIMPLE table: c type: ALL possible_keys: PRIMARY Note that the third row shows the key: NULL eq_ref access. Even though there was an index available which could key_len: NULL ref: NULL rows: 16 Extra: be used (we do a WHERE on the film.title field, which has an index on *************************** 2. row *************************** select_type: SIMPLE table: fc it), the optimizer chooses to use the type: ref possible_keys: PRIMARY,fk_film_category_category PRIMARY key to fulfill the select key: fk_film_category_category key_len: 1 request. Why? It viewed the 16 ref: sakila.c.category_id rows: 1 rows in the category table and Extra: Using index decided that the quickest way to *************************** 3. row *************************** select_type: SIMPLE access the data through the join table: f type: eq_ref fields in the film_category table. possible_keys: PRIMARY,idx_title key: PRIMARY These 16 rows is less than the 46 key_len: 2 ref: sakila.fc.film_id rows returned from the title index rows: 1 which match the query filter Extra: Using where Copyright MySQL AB The World’s Most Popular Open Source Database 20
  • 21. The importance of isolating indexed fields mysql> EXPLAIN SELECT * FROM film WHERE title LIKE 'Tr%'G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: film Nice. In the top query, we have a type: range possible_keys: idx_title fast range access on the indexed key: idx_title field key_len: 767 ref: NULL rows: 15 Extra: Using where mysql> EXPLAIN SELECT * FROM film WHERE LEFT(title,2) = 'Tr' G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: film Oops. In the bottom query, we type: ALL possible_keys: NULL have a slower full table scan key: NULL because of the function key_len: NULL ref: NULL operating on the indexed field rows: 951 (the LEFT() function) Extra: Using where Copyright MySQL AB The World’s Most Popular Open Source Database 21
  • 22. index_subquery and unique_subquery ● Appear when you use subqueries in your SELECT statement ● Subqueries yielding a unique set of data will produce unique_subquery, otherwise index_subquery ● unique_subquery is slightly better performing because the optimizer can entirely replace the subquery with a set of constants ● So it becomes a range condition ● Generally, a join will be better performing though... ● Let's see it in action Copyright MySQL AB The World’s Most Popular Open Source Database 22
  • 23. unique_subery access type example mysql> EXPLAIN SELECT * FROM rental r -> WHERE r.customer_id IN ( The outer table (rental) is accessed -> SELECT customer_id FROM customer -> WHERE last_name LIKE 'S%') G via a full table scan, and for each *************************** 1. row *************************** a WHERE filter record in the table, id: 1 select_type: PRIMARY is applied against a set of constant table: r customer_id values determined type: ALL from the unique_subquery result in possible_keys: NULL key: NULL the bottom select. key_len: NULL ref: NULL rows: 15646 Note that the select_type shows Extra: Using where DEPENDENT SUBQUERY. This is *************************** 2. row *************************** as the technically incorrect, id: 2 select_type: DEPENDENT SUBQUERY subquery is not a correlated table: customer subquery, but rather returns a list of type: unique_subquery possible_keys: PRIMARY,idx_last_name constants... key: PRIMARY key_len: 2 Also, the strategy doesn't take ref: func rows: 1 advantage of the index on Extra: Using index; Using where customer.last_name... Copyright MySQL AB The World’s Most Popular Open Source Database 23
  • 24. Rewriting the subquery as a standard join mysql> EXPLAIN SELECT * FROM rental r -> INNER JOIN customer c The standard join gives an -> ON r.customer_id=c.customer_id -> WHERE last_name LIKE 'S%' G entirely different query execution plan (and a faster *************************** 1. row *************************** id: 1 select_type: SIMPLE one) even though the table: c results of the query are type: range identical. possible_keys: PRIMARY,idx_last_name key: idx_last_name key_len: 137 Suggestion: ref: NULL rows: 54 Extra: Using where Rewrite subqueries *************************** 2. row *************************** correlated (especially id: 1 select_type: SIMPLE subqueries) into standard table: r joins type: ref possible_keys: idx_fk_customer_id key: idx_fk_customer_id key_len: 2 ref: sakila.c.customer_id rows: 13 Extra: Copyright MySQL AB The World’s Most Popular Open Source Database 24
  • 25. The select_type Column ● select_type is mostly just informative, but watch for the following: ● DEPENDENT SUBQUERY ● Means you've used a correlated subquery ● But can show non-correlated subqueries as dependent... ● Ensure there isn't a more efficient way of joining the information ● UNCACHEABLE SUBQUERY ● Similar to DEPENDENT SUBQUERY, but means that for each matched row in the outer query, the subquery must be re-evaluated ● For instance, if you use a user variable (@my_var) in your subquery Copyright MySQL AB The World’s Most Popular Open Source Database 25
  • 26. Effects of GROUP BY and ORDER BY ● GROUP BY and ORDER BY: ● Will produce “Using filesort” and/or “Using temporary” in the Extra column only when an index cannot be used for the grouping/sorting ● Let's see the difference between group by selects on indexed vs. non-indexed fields... Copyright MySQL AB The World’s Most Popular Open Source Database 26
  • 27. Effects of GROUP BY and ORDER BY mysql> EXPLAIN SELECT r.staff_id, COUNT(*) -> FROM rental r GROUP BY r.staff_id G *************************** 1. row *************************** id: 1 select_type: SIMPLE table: r type: index The top query, since possible_keys: NULL it groups on an key: idx_fk_staff_id key_len: 1 indexed field, does ref: NULL not require a filesort rows: 15646 and temporary Extra: Using index storage to do the mysql> EXPLAIN SELECT r.return_date, COUNT(*) sort/group that the -> FROM rental r GROUP BY r.return_date G bottom query does, *************************** 1. row *************************** id: 1 which groups on a select_type: SIMPLE non-indexed field. table: r type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 15646 Extra: Using temporary; Using filesort Copyright MySQL AB The World’s Most Popular Open Source Database 27
  • 28. Views ● Evaluated into an underlying SELECT statement ● WHERE expression can be applied on the view, which is then translated into a WHERE expression on the underlying table(s) ● But, what does the EXPLAIN return for a view? and... ● Does it differ from an EXPLAIN on an identical SELECT the underlying tables? ● Let's see... Copyright MySQL AB The World’s Most Popular Open Source Database 28
  • 29. The sales_by_film_category view CREATE VIEW sales_by_film_category AS SELECT c.name AS category , SUM(p.amount) AS total_sales FROM payment AS p INNER JOIN rental AS r ON p.rental_id = r.rental_id INNER JOIN inventory AS i ON r.inventory_id = i.inventory_id INNER JOIN film AS f ON i.film_id = f.film_id INNER JOIN film_category AS fc ON f.film_id = fc.film_id INNER JOIN category AS c ON fc.category_id = c.category_id GROUP BY c.name ORDER BY total_sales DESC; The view joins a number of tables together to make it easier and less cumbersome to query for the information above. Instead of executing the above statement, you would execute SELECT * FROM sales_by_film_category; Copyright MySQL AB The World’s Most Popular Open Source Database 29
  • 30. EXPLAIN on a view mysql> EXPLAIN SELECT * FROM sales_by_film_category; +----+-------------+------------+--------+---------------------------------+ | id | select_type | table | type | Extra | +----+-------------+------------+--------+---------------------------------+ | 1 | PRIMARY | <derived2> | ALL | | | 2 | DERIVED | c | ALL | Using temporary; Using filesort | | 2 | DERIVED | fc | ref | Using index | | 2 | DERIVED | f | eq_ref | Using index | | 2 | DERIVED | i | ref | Using index | | 2 | DERIVED | r | ref | Using index | | 2 | DERIVED | p | ref | Using where | +----+-------------+------------+--------+---------------------------------+ 7 rows in set (0.22 sec) I've abbreviated the output from above for brevity, but notice the plethora (yes, plethora) of DERIVED select types? Did you notice any derived tables (subqueries in the FROM clause) in the original view definition? Nope. This is because of the internal rewrite that occurs; the underlying select is turned into a set of derived subqueries that can be independently filtered using a WHERE expression. What happens if we remove the SELECT * and replace with a SELECT category? Will the EXPLAIN output change? Copyright MySQL AB The World’s Most Popular Open Source Database 30
  • 31. EXPLAIN on a view with specified column mysql> EXPLAIN SELECT category FROM sales_by_film_category; +----+-------------+------------+--------+---------------------------------+ | id | select_type | table | type | Extra | +----+-------------+------------+--------+---------------------------------+ | 1 | PRIMARY | <derived2> | ALL | | | 2 | DERIVED | c | ALL | Using temporary; Using filesort | | 2 | DERIVED | fc | ref | Using index | | 2 | DERIVED | f | eq_ref | Using index | | 2 | DERIVED | i | ref | Using index | | 2 | DERIVED | r | ref | Using index | | 2 | DERIVED | p | ref | Using where | +----+-------------+------------+--------+---------------------------------+ 7 rows in set (0.25 sec) As you can see, there is no change at all in the EXPLAIN output, because of the underlying rewrite happening, there are fewer optimizations that we can use with views. In general, views will perform worse than an identical SELECT on the underlying tables. However, depending on your situation, the ease of using the view may be worth the performance impact. Copyright MySQL AB The World’s Most Popular Open Source Database 31
  • 32. Closing Arguments ● EXPLAIN EXTENDED ● Gives more information on the query execution plan produced for more complex queries. Issue EXPLAIN EXTENDED SELECT ..., and then SHOW WARNINGS; ● SHOW PROFILE ● Patch committed by Jeremy Cole will be going into the MySQL 5.0.35 Community Server, to be released shortly ● Provides fine-tuned profiling information on disk I/O and various internal state changes during query parsing and execution. Check out: http://jcole.us/blog/archives/category/mysql/ Copyright MySQL AB The World’s Most Popular Open Source Database 32
  • 33. MySQL Conference & Expo 2007 April 23-26, Santa Clara, California Over 100 Sessions & Tutorials • Performance Tuning & Benchmarks • Clustering, Replication, & Scale-Out • Data Warehousing, Reporting & BI • Security & Administration • PHP, LAMP, & MySQL • Web 2.0, Ajax, Ruby • And Much More… http://www.mysqlconf.com