Archive for July, 2007

Introducing MySQL Visual Explain

Download MySQL Visual Explain

If you’ve ever wished you could see MySQL’s EXPLAIN output formatted as a tree, now you can. MySQL Visual Explain transforms EXPLAIN output into a hierarchical view of the query plan, which is significantly easier to read and understand.

What it does

MySQL Visual Explain is a command-line tool, not a Graphical User Interface (GUI). You can use it two ways:

  • Give it a query and some connection options, and it will connect and EXPLAIN the query, then show you the result as a tree.
  • Give it the output of EXPLAIN in any of several formats, and it will parse it and turn it into a tree.

Here’s a simple example. Given the following query,

select actor_id,
   (select count(film_id) from sakila.film join sakila.film_actor using(film_id))
from sakila.actor;

You get this EXPLAIN output:

+----+-------------+------------+-------+----------------+--------------------+---------+---------------------+------+-------------+
| id | select_type | table      | type  | possible_keys  | key                | key_len | ref                 | rows | Extra       |
+----+-------------+------------+-------+----------------+--------------------+---------+---------------------+------+-------------+
|  1 | PRIMARY     | actor      | index | NULL           | PRIMARY            | 2       | NULL                |  200 | Using index | 
|  2 | SUBQUERY    | film       | index | PRIMARY        | idx_fk_language_id | 1       | NULL                |  951 | Using index | 
|  2 | SUBQUERY    | film_actor | ref   | idx_fk_film_id | idx_fk_film_id     | 2       | sakila.film.film_id |    2 | Using index | 
+----+-------------+------------+-------+----------------+--------------------+---------+---------------------+------+-------------+

MySQL Visual Explain turns this into the following query execution plan:

SUBQUERY
+- JOIN
|  +- Index lookup
|  |  key            film_actor->idx_fk_film_id
|  |  possible_keys  idx_fk_film_id
|  |  key_len        2
|  |  ref            sakila.film.film_id
|  |  rows           2
|  +- Index scan
|     key            film->idx_fk_language_id
|     possible_keys  PRIMARY
|     key_len        1
|     rows           951
+- Index scan
   key            actor->PRIMARY
   key_len        2
   rows           200

You should read this as a depth-first tree traversal. In other words, the root of the tree is the output node — the last thing that happens in query execution.

As I said, this is a simple example. When your queries have many subqueries and/or UNIONs, you quickly get much more complicated EXPLAIN output, which is very hard to understand. It’s much easier to read the tree representation for complex queries. Here are thumbnails of the query execution plans of some real queries from a project I’ve worked on:

MySQL Visual Explain output on a complex queryMySQL Visual Explain output on a complex query

The corresponding EXPLAIN output is very hard to understand, even though I’ve become an expert on EXPLAIN. I can understand the tree view without trouble. I don’t think it matters how much of an expert I am, a tree view is always going to be easier to understand.

How it works

MySQL Visual Explain tries to reverse-engineer EXPLAIN by re-ordering and dividing the input into parent/child relationships. How exactly it happens is complex, though it can be expressed in code fairly succinctly. I wanted to write this tool nearly a year ago, but after studying EXPLAIN for a while, I found I just didn’t understand it well enough. Then this spring at the MySQL Conference and Expo 2007, I saw a talk on the Query Optimizer by Timour Katchaounov, who works on the optimizer team. Timour helped me grasp how MySQL executes queries. Most importantly, he showed a diagram of the execution plan as a left-deep tree. I always assumed the query execution plan was a bushy tree, but once I saw the left-deep tree I understood more about how MySQL works (for example, I now understand why MySQL doesn’t support FULL OUTER JOIN).

The crucial bridge between that and understanding EXPLAIN was a slide that showed the nodes of the tree mapped to rows in EXPLAIN. This made me see how to approach the problem. After spending hours reading the MySQL manual and source code, and studying many examples, I slowly understood how to go backwards from EXPLAIN to a tree.

It is not as simple as it sounds! There are many details, such as how to decide which nodes should be children of which other nodes (when there are no subqueries or UNIONs, of course it’s trivial). EXPLAIN’s output can be quite complex, and a moderately complicated query takes me a few minutes to reverse-engineer by hand — and most of the time I get it wrong. Maybe I can write the details in another blog post, or contribute them to MySQL’s documentation or the MySQL Forge wiki.

Download it

You can get the goodies from the Sourceforge MySQL Toolkit project page and read the documentation online at the MySQL Toolkit homepage.

If you find bugs

I couldn’t have written this tool without unit tests, especially since I had to start over twice when I found I was misunderstanding something major (that’s a huge plug for test-driven development). If you find a query it transforms wrong, please report it via the project’s Sourceforge bug tracking system. Please give the query and EXPLAIN output, so I can add it to the test suite.

Future plans

MySQL themselves, and many community members, have sometimes discussed the need for a tree view of EXPLAIN. I sincerely hope they implement that feature and make this little tool obsolete in future versions of MySQL. I also understand MySQL is trying to add more information to EXPLAIN. Currently it’s not possible to get a complete query execution plan from EXPLAIN, because it doesn’t show you everything the server does while executing the query. If MySQL adds information, I’ll update this tool. I have a feature request pending to show when a GROUP BY happens, for example.

I also specifically wrote this tool to be useful as a module, not just a command-line utility. This makes it possible for you to use the module in your own programs. I have a few ideas for this myself, though I may not get time to implement them.

Your support appreciated

Though the end result makes it look easy, this was a seriously hard project that took many evenings and weekends of research, testing, and coding, with many false starts. If you feel inclined, there’s a “support” link in the navigation bar at the top of this page! (For those of you who tried to send me something and it got returned, I’ve fixed that issue).

Technorati Tags:, , , , ,

You might also like:

  1. How to avoid an extra index scan in MySQL
  2. How to sync tables in master-master MySQL replication
  3. MySQL Query Profiler
  4. Progress on Maatkit bounty, part 3
  5. A case study in profiling queries in MySQL

How to avoid an extra index scan in MySQL

Is your MySQL server doing an extra index scan on queries that need to check a key for matches or NULL? It’s easy for this to happen accidentally, but it’s also easy to fix, especially in MySQL 5.0 and up. Here’s how.

If you read the manual page for EXPLAIN, you’ll see the ref_or_null “join type” (I think “access type” is really a better term) mentioned. If you see this in EXPLAIN, it means MySQL has to search the index for matches, then search again for NULLs. If there are no NULLs in that column, and MySQL knew that, it could avoid the extra search.

You might see this in subqueries or when you use elaborate JOIN clauses, or even when you use a simple WHERE clause. For example, here’s a query that will do a ref_or_null access plan on the Sakila sample database:

explain select * from sakila.film
where original_language_id = 3 or original_language_id is null\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: film
         type: ref_or_null
possible_keys: idx_fk_original_language_id
          key: idx_fk_original_language_id
      key_len: 2
          ref: const
         rows: 476
        Extra: Using where

Why does this happen? Simple: the indexed column is defined as NULLable. Here’s a query you can use to find all such columns:

select c.table_schema, c.table_name, c.column_name
from information_schema.columns as c
   inner join information_schema.key_column_usage using(table_schema, table_name, column_name)
where c.table_schema = 'sakila' and c.is_nullable = 'yes';
+--------------+------------+----------------------+
| table_schema | table_name | column_name          |
+--------------+------------+----------------------+
| sakila       | film       | original_language_id | 
| sakila       | payment    | rental_id            | 
+--------------+------------+----------------------+

If the column shouldn’t be allowed to be NULL, make sure you specify that in the column’s options! In fact, the original_language_id column probably should be defined as NULLable, but I commonly see columns defined as NULLable when they shouldn’t be. The performance penalty isn’t the end of the world, but it’s still worth fixing.

Technorati Tags:, , , , , ,

You might also like:

  1. Introducing MySQL Visual Explain
  2. What is a SQL blind insert?
  3. MySQL’s FEDERATED storage engine: Part 1

Ubuntu on Dell Inspiron 1501

I recently bought a Dell Inspiron 1501, which I got a great deal on thanks to the fine people at DealNews. The base system was $449 shipped, and I chose to upgrade the processor to dual AMD64s. But I didn’t buy the system that came with Ubuntu pre-installed; for whatever reason, the one that came with Windows offered a special discount (normally the Windows tax for otherwise identical machines appears to be around $150, and I’m certainly not going to run Windows).

Therefore, I was not sure Ubuntu would support all the hardware. It’s the same story it’s been for as long as I’ve been using computers: hardware manufacturers withhold specifications from the Free Software world, so there is always a chance something will be a trouble. The good news is, I’ve only noticed two very minor incompatibilities out of the box.

One is that the Fn+arrow keys won’t change my screen brightness, at least under XFCE. Strangely, my ancient Dell laptop had no trouble with that. I assume the old one was a hardware-controlled feature and this one needs some software support, but I could be wrong.

The other thing is the built-in wireless card, which isn’t supported with Ubuntu 7.04’s drivers out of the box. However, I quickly found a set of drivers for the Broadcom Corporation Dell Wireless 1390 card, and was up and running shortly thereafter. The only thing I had to do after installing the drivers was press the Fn+F2 key, which turns the card on.

Otherwise everything works brilliantly.

And now for a rant: click through to that page about the drivers, and you’ll see an example of what I consider the Ubuntu sudo disease. There’s even a screenshot of someone typing sudo uname -a and using sudo to remove a file he didn’t create with sudo. I think unfortunately, Ubuntu’s policy of allowing one to run any command with sudo has created a crop of people who don’t understand what should and shouldn’t be privileged; some of them seem to believe that ’sudo’ is what you type at the beginning of every command. It completely defeats the purpose and circumvents the security gained by not running as root. For my part, when I want to administer my system, I become root, do what I need to do, and then quit again. I rarely sudo any command other than sudo su -.

But that’s just me.

Technorati Tags:, , , ,

You might also like:

  1. How to set up dual monitors in Ubuntu on Dell Inspiron 1501
  2. Favorite USB wireless card for Ubuntu?
  3. How to set up Gentoo wireless networking on AMD64
  4. Firefox vs. Opera on slow hardware
  5. Credit card expiration dates should conform to standards

MySQL Toolkit version 675 released

Download MySQL Toolkit

I’ve just released changes to two of the tools in MySQL Toolkit. MySQL Table Checksum got some convenient functionality to help you recursively check slaves for bad replicated checksum chunks. MySQL Archiver got statistics-gathering functionality to help you optimize your archiving and purging jobs, plus a few important bug fixes.

Changes in MySQL Archiver:

  • Made –time suffix optional.
  • Added –statistics option to gather and print timing statistics.
  • Added signal handling so mysql-archiver exits cleanly when it can.
  • Changed exit status to 0 when –help is given.
  • Out-of-column-order primary keys were not ascended correctly.

Changes in MySQL Table Checksum:

  • Added –replcheck option to check –replicate results on slaves.
  • Added –recursecheck option to do –replcheck recursively.
Technorati Tags:, , , , , ,

You might also like:

  1. MySQL Toolkit version 848 released
  2. MySQL Toolkit released as one package
  3. MySQL Toolkit version 815 released
  4. MySQL Toolkit distribution 620 released
  5. Maatkit version 1314 released

innotop version 1.4.3 released

Download innotop

Version 1.4.3 of the innotop MySQL and InnoDB monitor is out. This release fixes some minor bugs and feature annoyances, and at last innotop has thorough documentation, available online!

What’s new

Here’s what’s new:

  • Added standard –version command-line option
  • Changed colors to cyan instead of blue; more visible on dark terminals.
  • Added information to the filter-choosing dialog.
  • Added column auto-completion when entering a filter expression.
  • Changed Term::ReadKey from optional to mandatory.
  • Clarified username in password prompting.
  • Ten thousand words of documentation! Documentation is embedded in innotop, installed as a man page, and available online.

Bugs fixed:

  • innotop crashed in W mode when InnoDB status data was truncated.
  • innotop didn’t display errors in tables if debug was enabled.
  • The colored() subroutine wasn’t being created in non-interactive mode.
  • Don’t prompt to save password except the first time.

What’s next

I don’t know how much time I’ll get to put into this in the coming months, but there’s already a lot of half-finished functionality in the Subversion repository, including the ability to write innotop plugins. If you’re interested, the code is in the trunk and in various branches.

Hopefully I’ll get time to work on some of that before the year is out.

Technorati Tags:, , , , ,

You might also like:

  1. Version 0.1.106 of innotop MySQL/InnoDB monitor released
  2. innotop version 1.0 released
  3. What to do when innotop crashes
  4. innotop 1.4.2 released
  5. Version 0.1.132 of innotop released

JavaScript Number Formatting Library v1.3 released

Download Number Formatting Library

I’ve updated my JavaScript Number Formatting Library to version 1.3. This release adds the ability to customize how not-a-number (NaN), positive infinity and negative infinity are formatted. All you need to do is set the appropriate constant in Number.prototype:

  • Number.prototype.NaN
  • Number.prototype.posInfinity
  • Number.prototype.negInfinity

For more documentation, see the original article on JavaScript number formatting.

Technorati Tags:, , , , , ,

You might also like:

  1. How to format numbers in JavaScript flexibly and efficiently
  2. JavaScript number-formatting library updated
  3. Javascript date parsing and formatting, Part 2
  4. JavaScript formatting library update
  5. JavaScript date parsing and formatting, Part 1

What I’ve been doing lately

I haven’t been blogging about the things I used to — how-tos and technical hacks — because I’ve been working quite hard on MySQL Toolkit and, believe it or not, innotop. I’ve made it possible to write innotop plugins, which have been very useful to our team at work, and I’m working on documentation. Plugins won’t make it into the upcoming release; it’ll just be bug fixes and documentation. These projects have taken up most of my free time.

I’ve also tentatively joined a group of people working on a very large, exciting, secret project which may consume the rest of my summer and/or much of the rest of the year. (I’ve been turning down consulting gigs and other projects because of this). If this secret project works out, I’ll be writing more about it here, you can count on that.

In the meantime, I’m still planning to finish some of the work I’ve started on MySQL Table Sync, which I continue to need because of a replication bug I haven’t been able to isolate.

Someday, maybe even soon, I might finish some of my 60+ drafts, such as “how to implement event listeners and notification in MySQL.” But I think the other projects I’m working on are much more important and beneficial to many more people, so I have prioritized them.

I had a slight glitch with my Amazon wishlist. I was on vacation and when I came back, I saw about half a dozen things purchased from it, but I haven’t received any of them (thank you, whoever you are!). I didn’t really understand how the wish list worked, so I didn’t know I needed to specify a shipping address. I assumed Amazon would send them to my primary shipping address. Well, apparently that didn’t work, and in the meantime I also realized Amazon was sending mail somewhere I couldn’t receive it, so I’m not sure what is really going on. I’ve specified an address now, and I’m hoping that takes care of it.

Technorati Tags:, ,

You might also like:

  1. A look at innotop’s new features
  2. MySQL Query Profiler 1.0.0 released
  3. innotop version 1.4.3 released

MySQL Table Checksum 1.1.9 released

Download MySQL Toolkit

This release fixes some bugs and improves the chunking functionality. MySQL Table Checksum had a few minor bugs and one major bug with the chunking functionality. I also rewrote the chunking, though the behavior is backwards compatible. I am very happy with the way it works now, and will probably not make any more incompatible changes to it. The changes enabled me to add support for chunking on float, double and decimal columns.

It still doesn’t support chunking on character-based columns, though I know now how I’ll do it if I do. Also, support for ENUM and SET shouldn’t be hard to add. I have no need for these features myself. If you need it, please file a bug report on the Sourceforge tracker.

Technorati Tags:

You might also like:

  1. MySQL Table Checksum 1.1.6 released
  2. MySQL Toolkit distribution 620 released
  3. MySQL Table Checksum 1.1.5 released
  4. MySQL Toolkit version 675 released
  5. MySQL Toolkit version 848 released

MySQL Toolkit distribution 620 released

Download MySQL Toolkit

MySQL Toolkit distribution 620 updates documentation and test suites, includes some major bug fixes and functionality changes, and adds one new tool to the toolkit. This article is mostly a changelog, with some added notes.

Many of the tools have matured and I just needed to make the documentation top-notch, but there’s still a lot to be done on the crucial checksumming and syncing tools. Time is in short supply for me right now, though. In fact, I actually finished this release on June 22, but wasn’t able to release it till just tonight!

Documentation is now maintained online at the MySQL Toolkit website, by the way.

mysql-archiver

Version 0.9.3

Changes

  • Added more hooks for plugins before and after archiving.
  • Documentation.
  • Made –time suffix optional.

Bugs fixed

  • MySQL Archiver could crash on a lock wait timeout when –txnsize was not set

mysql-deadlock-logger

Version 1.0.2

Incompatible changes

  • Changed the format of the –source and –dest options.

Changes

  • Documentation.

mysql-duplicate-key-checker

Version 1.0.4

  • Documentation.

mysql-find

Version 0.9.3

  • Documentation.

mysql-query-profiler and mysql-profile-compact

Version 1.1.2

  • Documentation

mysql-show-grants

Version 1.0.2

  • Documentation.

mysql-slave-restart

Version 0.9.2. This is an initial release of a new tool. I found myself in a situation where I needed to do some complex error-skipping on a slave (its relay logs got into an infinite loop). I have written throwaway scripts to skip, restart, check, skip several times in the past, but this situation called for something more complex. Again I realized I was three-quarters of the way to a more flexible, powerful tool many people might find useful, so I went ahead and put the extra effort into it.

It ended up helping me avoid re-snapshotting a slave with a ton of data, so it was worth it.

mysql-table-checksum and mysql-checksum-filter

This version fixes some badly optimized chunking queries. As I have mentioned in the past, the chunking behavior is preliminary and subject to change. This is still true, but this release is much smarter than the previous release! I have also fleshed out some methods of doing chunking on real-valued columns (float, decimal, and even character). I don’t know when I’ll get a chance to code, test, and release that.

Even though much remains to be done, MySQL Table Checksum is still a great way to check that your slaves have the same data as the master. (In fact, it’s the only way I know of — and MySQL employees themselves recommend MySQL Table Checksum).

Version 1.1.8

Changes

  • Documentation.
  • Support complex host definitions.
  • Added –explainhosts option to debug host definitions.
  • Added –explain option.
  • When exact chunking is impossible, mysql-table-checksum will use approximate.

Incompatible changes

  • Added required ‘boundaries’ column to checksum table for –replicate.

Bugs fixed

  • Chunking on temporal types defeated indexes.

mysql-table-sync

Version 0.9.5

  • Documentation.
Technorati Tags:, , , ,

You might also like:

  1. MySQL Table Checksum 1.1.6 released
  2. MySQL Table Checksum 1.1.9 released
  3. MySQL Toolkit version 896 released
  4. Maatkit version 1877 released
  5. MySQL Toolkit version 815 released