Anda di halaman 1dari 27

How to Install MySQL 5.

7 (on Windows, Mac OS X,


Ubuntu) and Get Started with SQL Programming
This article is applicable to MySQL 5.7. There are some changes in MySQL 5.7 over 5.6. Read
"How to Install MySQL 5.6" for installing MySQL 5.6.

This practical can be completed in a 3-hour session.

1. Introduction to Relational Database and SQL

1.1 Relational Databases

A relational database organizes data in tables. A table has rows (or records) and columns (or
fields). Tables are related based on common columns to eliminate data redundancy and ensure data
integrity.

Popular Relationship Database Management System (RDBMS) includes the commercial Oracle,
IBM DB2, Microsoft SQL Server and Access, SAP SyBase and Teradata; and the free MySQL,
PostgreSQL, Embedded Apache Derby (Java DB), mSQL (mini SQL), SQLite and Apache
OpenOffice's Base.

1.2 Structure Query Language (SQL)

A high-level language, called Structure Query Language (SQL), had been designed for interacting
with the relational databases. SQL defines a set of commands, such as SELECT, INSERT, UPDATE,
DELETE, CREATE TABLE, DROP TABLE, and etc.

Edgar F. Codd (of IBM) proposed the Relational Database Model in 1970. SQL, one of the earlier
programming language, was subsequently developed by Donald D. Chamberlin and Raymond F.
Boyce at IBM in the early 1970s. Oracle, subsequently, took it to a new height.

ANSI (American National Standard Institute) established the first SQL standard in 1986 (SQL-86
or SQL-87) - adopted by ISO/IEC as "ISO/IEC 9075" - followed in 1989 (SQL-89), 1992 (SQL-92
or SQL2), 1999 (SQL-99 or SQL3), 2003 (SQL-2003), 2006 (SQL-2006) and 2011 (SQL-2011).
However, most of the database vendors have their own directs, e.g., PL/SQL (Oracle), Transact-
SQL (Microsoft, SAP), PL/pgSQL (PostgreSQL).

1.3 SQL By Examples

A relational database system contains many databases. A database comprises one or more tables. A
table have rows (or records) and columns (or fields).

Suppose we have created a table called class101, in a database called studentdb, with 3 columns:
id, name and gpa. A column has a data type. We choose: INT (integer) for column id, FLOAT
(floating-point number) for gpa, and VARCHAR(50) (variable-length string of up to 50 characters) for
name. There are 4 rows in the table as follows:

Database: studentdb
Table: class101
+-----------+--------------------+-------------+
| id (INT) | name (VARCHAR(50)) | gpa (FLOAT) |
+-----------+--------------------+-------------+
| 1001 | Tan Ah Teck | 4.5 |
| 1002 | Mohammed Ali | 4.8 |
| 1003 | Kumar | 4.8 |
| 1004 | Kevin Jones | 4.6 |
+-----------+--------------------+-------------+

SQL provides an easy and intuitive way to interact with relational databases.

SELECT

-- SYNTAX
SELECT column1, column2, ... FROM tableName WHERE criteria
SELECT * FROM tableName WHERE criteria

-- EXAMPLES
SELECT name, gpa FROM class101
-- Select columns name and gpa from table class101.
+--------------+------+
| name | gpa |
+--------------+------+
| Tan Ah Teck | 4.5 |
| Mohammed Ali | 4.8 |
| Kumar | 4.8 |
| Kevin Jones | 4.6 |
+--------------+------+

SELECT * FROM class101


-- Select ALL columns from table class101.
-- The wildcard * denotes all the columns.
+------+--------------+------+
| id | name | gpa |
+------+--------------+------+
| 1001 | Tan Ah Teck | 4.5 |
| 1002 | Mohammed Ali | 4.8 |
| 1003 | Kumar | 4.8 |
| 1004 | Kevin Jones | 4.6 |
+------+--------------+------+

SELECT name, gpa FROM class101 WHERE gpa >= 4.7


-- Select columns name and gpa, where the rows meet the criteria.
-- You can compare numbers using =, >, <, >=, <=, <> (!=)
+--------------+------+
| name | gpa |
+--------------+------+
| Mohammed Ali | 4.8 |
| Kumar | 4.8 |
+--------------+------+

SELECT name, gpa FROM class101 WHERE name = 'Tan Ah Teck'


-- Full-match (= or !=) on string. Strings are enclosed in single quotes.
+-------------+------+
| name | gpa |
+-------------+------+
| Tan Ah Teck | 4.5 |
+-------------+------+

SELECT name FROM class101 WHERE name LIKE 'k%'


-- Use "LIKE" for string pattern-matching, with
-- wildcard % matches zero or more (any) characters;
-- wildcard _ matches one (any) character.
+-------------+
| name |
+-------------+
| Kumar |
| Kevin Jones |
+-------------+

SELECT * FROM class101 WHERE gpa > 4 AND name LIKE 'k%' ORDER BY gpa DESC, name
ASC
-- Use AND, OR, NOT to combine simple conditions.
-- Order the results in DESC (descending) or ASC (Ascending)
+------+-------------+------+
| id | name | gpa |
+------+-------------+------+
| 1003 | Kumar | 4.8 |
| 1004 | Kevin Jones | 4.6 |
+------+-------------+------+

DELETE

-- SYNTAX
DELETE FROM tableName WHERE criteria

-- EXAMPLES
DELETE FROM class101
-- Delete ALL rows from the table class101! Beware that there is NO UNDO!
DELETE FROM class101 WHERE id = 33
-- Delete rows that meet the criteria.

INSERT

-- SYNTAX
INSERT INTO tableName VALUES (firstColumnValue, ..., lastColumnValue) --
All columns
INSERT INTO tableName (column1, column2, ...) VALUES (value1, value2, ...) --
Selected Columns

-- Example
INSERT INTO class101 VALUES (1001, 'Tan Ah Teck', 4.5)
-- List value of all columns.
INSERT INTO class101 (name, gpa) VALUES ('Peter Jones', 4.55)
-- Missing fields will be set to their default values or NULL

UPDATE

-- SYNTAX
UPDATE tableName SET column = value WHERE criteria

-- EXAMPLES
UPDATE class101 SET gpa = 5.0 -- ALL rows
UPDATE class101 SET gpa = gpa + 1.0 WHERE name = 'Tan Ah Teck' -- Selected rows

CREATE TABLE

-- SYNTAX
CREATE TABLE tableName (column1Name column1Type, column2Name column2Type, ...)

-- EXAMPLES
CREATE TABLE class101 (id INT, name VARCHAR(50), gpa FLOAT)

DROP TABLE

-- SYNTAX
DROP TABLE tableName

-- EXAMPLES
DROP TABLE class101 -- Delete the table. Beware that there is No UNDO!!!

Notes:

1. Case Sensitivity: SQL keywords, names (identifiers), strings may or may not be case-
sensitive, depending on the implementation.
o In MySQL, the keywords are NOT case-sensitive. For clarity, I show the keywords
in uppercase in this article.
o For programmers, it is BEST to treat the names (identifiers) and strings as case-
sensitive.
[In MySQL, column-names are always case insensitive; but table-names are case-
sensitive in Unix, but case-insensitive in Windows (confused!!). Case-sensitivity in
string comparison depends on the collating sequence used (?!).]
2. Quotes for String: SQL strings are enclosed in single quotes, but most implementations
(such as MySQL) also accept double quotes.

2. Introduction to MySQL Relational Database Management System (RDBMS)

SQL is a language for interacting with relational databases. On the other hand, MySQL is a
software system - a Relational Database Management System.

MySQL is one of the most used, and possibly the best industrial-strength, open-source and free
Relational Database Management System (RDBMS). MySQL was developed by Michael "Monty"
Widenius and David Axmark in 1995. It was owned by a Swedish company called MySQL AB,
which was bought over by Sun Microsystems in 2008. Sun Microsystems was acquired by Oracle in
2010.

MySQL is successful, not only because it is free and open-source (there are many free and open-
source databases, such as Apache Derby (Java DB), mSQL (mini SQL), SQLite, PostgreSQL and
Apache OpenOffice's Base), but also for its speed, ease of use, reliability, performance,
connectivity (full networking support), portability (run on most OSes, such as Unix, Windows,
Mac), security (SSL support), small size, and rich features. MySQL supports all features expected
in a high-performance relational database, such as transactions, foreign key, replication, subqueries,
stored procedures, views and triggers.

MySQL is often deployed in a LAMP (Linux-Apache-MySQL-PHP), WAMP (Windows-Apache-


MySQL-PHP), or MAMP (Mac-Apache-MySQL-PHP) environment. All components in LAMP is
free and open-source, inclusive of the Operating System.

The mother site for MySQL is www.mysql.com. The ultimate reference for MySQL is the "MySQL
Reference Manual", available at http://dev.mysql.com/doc. The reference manual is huge - the PDF
has over 3700 pages!!!
MySQL operates as a client-server system over TCP/IP network. The server runs on a machine with
an IP address, on a chosen TCP port number. The default TCP port number for MySQL is 3306.
Users can access the server via a client program, connecting to the server at the given IP address
and TCP port number.

A MySQL database server contains one or more databases. A database contains one or more tables.
A table consists of rows (or records) and columns (or fields).

3. How to Install MySQL 5.7 and Get Started with SQL Programming

I want you to install MySQL on your own machine, because I want you to learn how to install,
customize and operate complex industrial software system. Installation could be the hardest part in
this exercise.

3.1 Step 1: Download and Install MySQL

For Windows

1. Download MySQL ZIP ARCHIVE from http://dev.mysql.com/downloads/mysql/:


1. Choose "General Available (GA) Releases" tab.
2. In "Select Platform", choose "Microsoft Windows".
3. Under "Other Downloads", download "Windows (x86, 64-bit), ZIP ARCHIVE" or
"Windows (x86, 32-bit), ZIP ARCHIVE". (You can check whether your Windows is
32-bit or 64-bit from "Control Panel" System System System Type.)
4. There is NO need to "Sign-up" - Just click "No thanks, just start my downloads!".
2. Create a project directory, say "d:\myProject" or "c:\myProject".
UNZIP the downloaded file into your project directory. MySQL will be unzipped as
"d:\myProject\mysql-5.7.{xx}-winx64".
For ease of use, we shall shorten and rename the directory to "d:\myProject\mysql". Take
note and remember your MySQL installed directory!!!
3. (NEW since MySQL 5.7.7) Initialize the database: Start a CMD (as administrator) and issue
these commands:
4. // Change directory to the MySQL installed directory
5. // Suppose that your MySQL installed directory is d:\myProject\mysql
6. d:
7. cd \myProject\mysql\bin
8.
9. // Initialize the database. Create a root user without password. Show the
message on console
10. mysqld --initialize --console
11. ......
...... [Note] A temporary password is generated for root@localhost:
xxxxxxxx

During the installation, a superuser called root is created with a temporary random
password, as shown above. TAKE NOTE of the root's PASSWORD, COPY and save it
somewhere, and Take a Picture!!!!

12. If you make a mistake somewhere, delete the entire MySQL directory, and repeat step 2 and
3.

For Mac OS X

1. Download the MySQL "DMG Archive" from http://dev.mysql.com/downloads/mysql/:


1. Choose "General Available (GA) Releases" tab.
2. In "Select Platform", choose the "Mac OS X".
3. Select the appropriate "DMG Archive" for your specific Mac OS version:
Click the Apple logo "About this Mac" to check your Mac OS version.
Read http://support.apple.com/kb/ht3696 to check if your Mac OS is 32-bit
or 64-bit.

For example, for Lion (10.7) and Core i7 processor, choose "Mac OS X ver. 10.7
(x86, 64-bit), DMG Archive (117.5M)".

4. There is NO need to "Sign-up" - Just click "No thanks, just start my download".
2. To install MySQL:
1. Go to "Downloads" Double-click ".dmg" file downloaded.
2. Double-click the "mysql-5.7.{xx}-osx10.x-xxx.pkg"
3. Follow the screen instructions to install MySQL. During the installation, a superuser
called root is created with a temporary random password. TAKE NOTE of the
root's PASSWORD, COPY and save it somewhere, and Take a picture!!!!
4. MySQL will be installed in "/usr/local/mysql". Take note of this installed
directory!!
5. Eject the ".dmg" file.
3. If you make a mistake somewhere, stop the server (Click Apple Icon System Preferences
MySQL Stop), remove the directories "/usr/local/mysql-5.7.{xx}...", and re-run
the installation. Re-start the server (Click Apple Icon System Preferences MySQL
Start). You may need to re-start your machine.

For Ubuntu

Refer to "How to install MySQL 5 on Ubuntu".

I shall assume that MySQL is installed in directory d:\myProject\mysql (for Windows) or


/usr/local/mysql (for Macs). But you need to TAKE NOTE OF YOUR MySQL INSTALLED
DIRECTORY. Hereafter, I shall denote the MySQL installed directory as <MYSQL_HOME> in this
article.
3.2 Step 3: Start the Server

The MySQL is a client-server system. The database is run as a server application. Users access the
database server via a client program, locally or remotely thru the net, as illustrated:

1. The server program is called "mysqld" (with a suffix 'd', which stands for daemon - a
daemon is a non-interactive process running in the background).
2. The client program is called "mysql" (without the 'd').

The programs mysqld and mysql are kept in the "bin" sub-directory of the MySQL installed
directory.

Startup Server

For Windows

To start the database server, launch a CMD shell:

-- Change the current directory to MySQL's "bin" directory


-- Assume that the MySQL installed directory is "d:\myProject\mysql"
d: -- Set the current drive
cd \myProject\mysql\bin -- Change Directory to the MySQL's bin directory

-- Start the MySQL Database Server


mysqld --console
......
......
XXXXXX XX:XX:XX [Note] mysqld: ready for connections.
Version: '5.6.xx-community' socket: '' port: 3306 MySQL Community Server
(GPL)

Notes: The --console option directs the server output messages to the console. Without this
option, you will see a blank screen.

For Mac OS X

The EASY WAY: Via the graphical control. Click Apple Icon System Preferences MySQL
Start.

The MySQL database server is now started, and ready to handle clients' requests.
Anything that can possibly go wrong, does! Read "Common Problems in Starting the MySQL
Server after Installation".

Shutdown Server

For Windows

The quickest way to shut down the database server is to press Ctrl-C to initiate a normal shutdown.
DO NOT KILL the server via the window's CLOSE button.

Observe these messages from the MySQL server console:

XXXXXX XX:XX:XX [Note] mysqld: Normal shutdown


......
XXXXXX XX:XX:XX InnoDB: Starting shutdown...
XXXXXX XX:XX:XX InnoDB: Shutdown completed; log sequence number 0 44233
......
XXXXXX XX:XX:XX [Note] mysqld: Shutdown complete

For Mac OS X

The EASY WAY: Via the graphical control. Click Apple Icon System Preferences MySQL
Stop.

WARNING: You should properly shutdown the MySQL server. Otherwise, you might corrupt the
database and might have problems restarting it. BUT, if you encounter problem shutting down the
server normally, you may kill the "mysqld" process in Task Manager (for Windows); or Activity
Monitor (for Mac OS X); or System Monitor (for Ubuntu).

3.3 Step 4: Start a Client

Recall that the MySQL is a client-server system. Once the server is started, one or more clients can
be connected to the database server. A client could be run on the same machine (local client); or
from another machine over the net (remote client).

To login to the MySQL server, you need to provide a username and password. During the
installation, MySQL creates a superuser called "root" with a temporary random password. I hope
that you have taken note of this password!!

The MySQL installation provides a command-line client program called "mysql". (Recall that the
server program is called "mysqld" with a suffix 'd'; the client program does not have the suffix 'd').

Let's start a command-line client with the superuser "root".

First, make sure that the server is running. See previous step to re-start the server if it has been
shutdown.

For Windows

Start another NEW CMD shell to run the client:

-- Change the current directory to <MYSQL_HOME>\bin.


-- Assume that the MySQL is installed in "d:\myProject\mysql".
d: -- Change the current drive
cd \myProject\mysql\bin -- Change Directory to YOUR MySQL's "bin" directory

-- Start a client as superuser "root"


mysql -u root -p
Enter password:
// Enter the root's password set during installation.
// NOTHING will be shown for maximum security.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.1.39-community MySQL Community Server (GPL)
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>
-- Client started. The prompt changes to "mysql>".
-- You can now issue SQL commands.

For Mac OS X

Open a NEW "Terminal" and issue these commands to start a MySQL client with superuser root:

-- Change the current directory to <MYSQL_HOME>\bin.


cd /usr/local/mysql/bin

-- Start a client with superuser "root"


./mysql -u root -p
Enter password:
// Enter the root's password set during installation.
// NOTHING will be shown for maximum security.
Welcome to the MySQL monitor. Commands end with ; or \g.
......
mysql>
-- Client started. The prompt changes to "mysql>".
-- You can now issue SQL commands.

(Skip Unless...) Read "Common Problems in Starting the MySQL Client".

3.4 Step 5: Change the Password for the Superuser "root"

As mentioned earlier, the MySQL installation creates a superuser called "root" with a temporary
random password. "root" is a privileged user that can do anything, including deleting all the
databases. You are required to change the root's password after logging in.

Change the Password for "root"

Let's continue with our client session started earlier.

-- Change password for 'root'@'localhost'. Replace xxxx with your chosen


password
-- (For my students: use xxxx as the password. Otherwise,
-- you will ask me what is your password next week.)
-- Take note that strings are to be enclosed by a pair of single-quotes.
mysql> alter user 'root'@'localhost' identified by 'xxxx';
Query OK, 0 rows affected (0.00 sec)

-- logout and terminate the client program


mysql> quit
Bye

Re-Start a Client as "root" with the New Password


We have just changed the password for root and exited the client. Start a client and login as root
again. Enter the password when prompted.

For Windows

-- Change the current working directory to <MYSQL_HOME>\bin


mysql -u root -p
Enter password: // Type your password and enter. NOTHING will be shown for
security.
Welcome to the MySQL monitor.
......
mysql>
-- client started, ready to issue SQL command

For Mac OS X

-- Change the current working directory to /usr/local/mysql/bin


cd /usr/local/mysql/bin
./mysql -u root -p
Enter password: // Type your password and enter. NOTHING will be shown for
security.
Welcome to the MySQL monitor.
......
mysql>
-- client started, ready to issue SQL command

3.5 Step 6: Create a New User

The superuser "root" is privileged, which is meant for database administration and is not meant for
operational. We shall create a new user - let's call it "myuser" - with a lesser privilege. To create a
new user, start a client with superuser "root":

-- Start a client, IF IT IS NOT STARTED


mysql -u root -p // Windows
./mysql -u root -p // Mac OS X

-- Create a new user called "myuser", which can login from localhost, with
password "xxxx"
mysql> create user 'myuser'@'localhost' identified by 'xxxx';
Query OK (0.01 sec)

-- Grant permission to myuser


mysql> grant all on *.* to 'myuser'@'localhost';
Query OK (0.01 sec)

mysql> quit

Explanation

CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'xxxx'


We use the command "create user" to create a new user called 'myuser'@'localhost',
who can login to the server locally from the same machine (but not remotely from another
machine), with password "xxxx".
GRANT ALL ON *.* TO 'myuser'@'localhost'
The newly created user has NO privilege to perform any database operation including
select. We use the "grant" command to grant "all" the privileges (including select,
insert, delete, and so on) to this new user on ALL the databases and ALL the tables ("on
*.*"). This new user, in practice, has the same privilege as root, except that it cannot issue
grant command. For production, you should grant only the necessary privileges on selected
databases and selected tables, e.g., "grant select, insert, update on studentdb.*" - it
can issue select, insert and update (but no delete, create/drop table) on ALL the
tables of the database studentdb only.

3.6 Step 7: Create a new Database, a new Table in the Database, Insert Records, Query and
Update

A MySQL server contains many databases. A database contains many tables. A table contains rows
(records) and columns (fields).

Let's create a database called "studentdb", and a table called "class101" in the database. The table
shall have three columns: id (of the type INT - integer), name (of the type VARCHAR(50) - variable-
length string of up to 50 characters), gpa (of the type FLOAT - floating-point number).

CAUTION: Programmers don't use blank and special characters in names (database names, table
names, column names). It is either not supported, or will pose you many more challenges.

TIPS: Before we proceed, here are some tips on using the client:

You need to terminate your command with a semicolon (;), which sends the command to
the server for processing. E.g.,
mysql> select * from class101 ;
-- Send the command to the server for processing

You can use \c to cancel (abort) the current command. E.g.,


mysql> select * from class101 \c
-- abort (cancel) the command

A command can span several lines. The prompt for subsequent lines changes to ->. You
need to terminate the command with a semicolon (;). E.g.,
mysql> select *
-> from class101
->
-> ;
-- A command can span several lines, ended with a semicolon.

If you open a single quote, without closing it, the prompt changes to '>. For example,
mysql> select 'xxx
'> '\c // close the single-quote and abort

You can use up/down arrow keys to retrieve the previous/next commands (from the history
commands).
(For Windows) You should enable copy/paste functions of CMD shell. To enable
copy/paste, click the CMD's icon Properties Options Edit Options Check
"QuickEdit Mode". You can then select the desired texts and use a "right-click" to copy the
selected text; another "right-click" to paste.

Let's start a client with our newly-created user "myuser".

-- Start a client, IF IT IS NOT STARTED


-- cd to the MySQL's bin directory
mysql -u myuser -p // Windows
./mysql -u myuser -p // Mac OS X
-- Create a new database called "studentdb"
mysql> create database if not exists studentdb;
Query OK, 1 row affected (0.08 sec)

-- list all the databases in this server


mysql> show databases;
+--------------------+
| Database |
+--------------------+
| ...... |
| studentdb |
| ...... |
+--------------------+
x rows in set (0.07 sec)

-- Use "studentdb" database as the default database


-- You can refer to tables in the default database by the tablename alone,
instead of databasename.tablename
mysql> use studentdb;
Database changed

-- Remove the table "class101" in the default database if it exists


mysql> drop table if exists class101;
Query OK, 0 rows affected (0.15 sec)

-- Create a new table called "class101" in the default database


-- with 3 columns of the specified types
mysql> create table class101 (id int, name varchar(50), gpa float);
Query OK, 0 rows affected (0.15 sec)

-- List all the tables in the default database "studentdb"


mysql> show tables;
+---------------------+
| Tables_in_studentdb |
+---------------------+
| class101 |
+---------------------+
1 row in set (0.00 sec)

-- Describe the "class101" table (list its columns' definition)


mysql> describe class101;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | varchar(50) | YES | | NULL | |
| gpa | float | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
3 rows in set (0.04 sec)

-- Insert a row into "class101" table.


-- Strings are to be single-quoted. No quotes for INT and FLOAT.
mysql> insert into class101 values (11, 'Tan Ah Teck', 4.8);
Query OK, 1 row affected (0.03 sec)

-- Insert another row


mysql> insert into class101 values (22, 'Mohamed Ali', 4.9);
Query OK, 1 row affected (0.03 sec)

-- Select all columns (*) from table "class101"


mysql> select * from class101;
+----+-------------+------+
| id | name | gpa |
+----+-------------+------+
| 11 | Tan Ah Teck | 4.8 |
| 22 | Mohamed Ali | 4.9 |
+----+-------------+------+
2 rows in set (0.00 sec)

-- Select columns from table "class101" with criteria


mysql> select name, gpa from class101 where gpa > 4.85;
+-------------+------+
| name | gpa |
+-------------+------+
| Mohamed Ali | 4.9 |
+-------------+------+
1 rows in set (0.00 sec)

-- Update selected records


mysql> update class101 set gpa = 4.4 where name = 'Tan Ah Teck';
Query OK, 1 row affected (0.05 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from class101;


+----+-------------+------+
| id | name | gpa |
+----+-------------+------+
| 11 | Tan Ah Teck | 4.4 |
| 22 | Mohamed Ali | 4.9 |
+----+-------------+------+
2 rows in set (0.00 sec)

-- delete selected records


mysql> delete from class101 where id = 22;
Query OK, 1 row affected (0.03 sec)

mysql> select * from class101;


+----+-------------+------+
| id | name | gpa |
+----+-------------+------+
| 11 | Tan Ah Teck | 4.4 |
+----+-------------+------+
1 rows in set (0.00 sec)

-- You can store SQL commands in a FILE (called SQL script) and run the script.
-- Use a programming text editor to CREATE a NEW FILE called "mycommands.sql"
-- containing the following three SQL statements.
-- (For Windows) Save the file under "d:\myProject".
-- (For Mac OS X) Save the file under "Documents".
insert into class101 values (33, 'Kumar', 4.8);
insert into class101 values (44, 'Kevin', 4.6);
Select * from class101;

-- Once you have created the file, you can use the following "source" command
-- to run the SQL script.
-- You need to provide the full path to the script.
-- (For Windows) The filename is d:\myProject\mycommands.sql.
-- (For Mac OS X) The filename is ~/Documents/mycommands.sql
mysql> source d:\myProject\mycommands.sql // For Windows
mysql> source ~/Documents/mycommands.sql // For Mac OS X
Query OK, 1 row affected (0.00 sec) -- INSERT command output
Query OK, 1 row affected (0.00 sec) -- INSERT command output
+------+-------------+------+ -- SELECT command output
| id | name | gpa |
+------+-------------+------+
| 11 | Tan Ah Teck | 4.4 |
| 33 | Kumar | 4.8 |
| 44 | Kevin | 4.6 |
+------+-------------+------+
3 rows in set (0.00 sec)

Exercises:

1. Select records with names starting with letter 'K'. (Hints: name like 'K%')
2. Select records with names NOT starting with letter 'K'. (Hints: name NOT like ...)
3. Select records with gpa between 4.35 and 4.65. (Hints: test-1 AND test-2)
4. Select records with names having a letter 'e'. (Hints: name like '%e%')
5. Select records with names having a letter 'e' or 'a'. (Hints: test-1 OR test-2)
6. Select records with names NOT having a letter 'e' or 'a'. (Hints: NOT (test-1 OR test-
2))
7. Select records with names having a letter 'e' and gpa 4.5.

(Skip Unless... ) Read "Common Problems in Using the mysql Client".

3.7 More Exercises

1. Show all the databases.


2. Create a new database called "ABCTrading".
3. Set the "ABCTrading" database as the default database.
4. Show all the tables in the default database.
5. Create a new table called "products" with the columns and type indicated below.
6. +-------+----------+-------------+----------+---------+
7. | id | category | name | quantity | price |
8. | (INT) | CHAR(3) | VARCHAR(20) | (INT) | (FLOAT) |
9. +-------+----------+-------------+----------+---------+
10. | 1001 | PEN | Pen Red | 5000 | 1.23 |
11. | 1002 | PEN | Pen Blue | 8000 | 1.25 |
12. | 1003 | PEN | Pen Black | 2000 | 1.25 |
13. | 1004 | PCL | Pencil 2B | 10000 | 0.49 |
14. | 1005 | PCL | Pencil 2H | 9000 | 0.48 |
+-------+----------+-------------+----------+---------+

15. Show the table description.


16. Insert the above records and list all the records.
17. List records with name containing "Pencil".
18. List records with price 1.0.
19. Increase the price of all items by 10%, and list all the records.
20. Remove "Pen Red" from the table, and list all the records.

4. Many-to-many Relationship
In a bookstore, a book is written by one or more authors; an author may write zero or more books.
This is known as a many-to-many relationship. It is IMPOSSIBLE to capture many-to-many
relationship in a SINGLE table with a fixed number of columns, without duplicating any piece of
information! For example, if you organize the data in the table below, you will not know how many
author columns to be used; and you need to repeat all the data for repeating authors.
The many-to-many relationship between books and authors can be modeled with 3 tables, as shown
below. A books table contains data about books (such as title and price); an authors table contains
data about the authors (such as name and email). A table called books_authors joins the books and
authors tables and captures the many-to-many relationship between books and authors.

Exercises

1. Create a database called "mybookstore".


2. Use "mybookstore" as the default database.
3. Create 3 tables "books", "authors", and "books_authors" in the database "mybookstore",
with column names and types as shown.
4. Insert the respective records into the tables. List the contents of each of the tables.
5. Try this query and explain the output:
6. SELECT books.title, books.price, authors.name
7. FROM books, books_authors, authors
8. WHERE books.isbn = books_authors.isbn
9. AND authors.authorID = books_authors.authorID
AND authors.name = 'Tan Ah Teck';

10. List all the books (title, price, qty) by "Tan Ah Teck" with price less than 20.
11. List all the authors (name and email) for the book title "Java for Dummies".
12. List all the books (title, price, qty) and all the authors (name and email) for books with
title beginning with "Java" (Hints: title LIKE 'Java%').

5. Backup and Restore Databases

5.1 Backup via "mysqldump" Utility Program

You can use the "mysqldump" utility program to back up the entire server (all databases), selected
databases, or selected tables of a database. The "mysqldump" program generates a SQL script that
can later be executed to re-create the databases, tables and their rows.
For example, the following command backups the entire "studentdb" database to a SQL script
called "backup_studentdb.sql".

For Windows

-- Start a NEW "cmd"


d:
cd \myProject\mysql\bin
mysqldump -u myuser -p --databases studentdb >
"d:\myProject\backup_studentdb.sql"

For Mac OS X

-- Start a NEW "terminal"


cd /usr/local/mysql/bin
./mysqldump -u myuser -p --databases studentdb >
~/Documents/backup_studentdb.sql
// ~ denotes the home directory of the current login user

Study the output file, which contains CREATE DATABASE, CREATE TABLE and INSERT statements to
re-create the database and tables dumped.

5.2 Restore via "source" command in a mysql client

You can restore from the backup by running the "source" command in a MySQL client. For
example, to restore the studentdb backup earlier:

For Windows

-- Start a MySQL client


d:
cd \myproject\mysql\bin
mysql -u myuser -p
-- Run the backup script to recreate the database
mysql> drop database if exists studentdb;
mysql> source d:\myProject\backup_studentdb.sql

For Mac OS X

-- Start a MySQL client


cd /usr/local/mysql/bin
./mysql -u myuser -p
-- Run the backup script to recreate the database
mysql> drop database if exists studentdb;
mysql> source ~/Documents/backup_studentdb.sql

6. Summary of Frequently-Used Commands


(For Windows) Starting MySQL Server and Client

-- Start the Server


cd path-to-mysql-bin
mysqld --console

-- Shutdown the Server


Ctrl-c

-- Start a Client
cd path-to-mysql-bin
mysql -u username -p

(For Mac OS X) Starting MySQL Server and Client

-- Start/shutdown the Server:


-- Use Graphical Control

-- Start a Client
cd /usr/local/mysql/bin
./mysql -u username -p

Frequently-used MySQL Commands

MySQL commands are NOT case sensitive.

-- General
; -- Sends command to server for processing (or \g)
\c -- Cancels (aborts) the current command

-- Database-level
DROP DATABASE databaseName; -- Deletes the database
DROP DATABASE IF EXISTS databaseName; -- Deletes only if it exists
CREATE DATABASE databaseName; -- Creates a new database
CREATE DATABASE IF NOT EXISTS databaseName; -- Creates only if it does not
exists
SHOW DATABASES; -- Shows all databases in this
server

-- Set default database.


-- Otherwise you need to use the fully-qualified name, in the form
-- of "databaseName.tableName", to refer to a table.
USE databaseName

-- Table-level
DROP TABLE tableName;
DROP TABLE IF EXISTS tableName;
CREATE TABLE tableName (column1Definition, column2Definition, ...);
CREATE TABLE IF NOT EXISTS tableName (column1Definition, column2Definition,
...);
SHOW TABLES; -- Shows all the tables in the default database
DESCRIBE tableName; -- Describes the columns for the table
DESC tableName; -- Same as above

-- Record-level (CURD - create, update, read, delete)


INSERT INTO tableName VALUES (column1Value, column2Value,...);
INSERT INTO tableName (column1Name, ..., columnNName)
VALUES (column1Value, ..., columnNValue);
DELETE FROM tableName WHERE criteria;
UPDATE tableName SET columnName = expression WHERE criteria;
SELECT column1Name, column2Name, ... FROM tableName
WHERE criteria
ORDER BY columnAName ASC|DESC, columnBName ASC|DESC, ...;

-- Running a script of MySQL statements


SOURCE full-Path-Filename
17 Key MySQL Config File Settings (MySQL 5.7 proof)
In MySQL by Aurimas MikalauskasDecember 4, 201532 Comments

When MySQL becomes too slow (or too unstable), temptation usually is to tweak the MySQL
configuration file. Indeed, its a good place to start. But if you ever looked at the available
configuration options, you know things can get messy MySQL now has over 450 configuration
variables for your consideration, that are not classified in any way, and neither of them are included
in the stock my.cnf. Its hard to know where to start!

Im hoping that this blog post will help you overcome the anxiety of tuning MySQL, whether youre
setting up a new server, or tuning an already running server for better performance.

Dont do it the way rookies do it


During the last 9 years Ive spent at Percona working as a MySQL performance and scalability
consultant, I found that customers often use the trial and error approach when tuning MySQL
configuration: they change a few things and check if it feels better.

This doesnt work! Problem is that by the time youre measuring how your application feels,
situation may have changed already. Plus you have to consider the warm up time and disregard any
overhead you see due to it. And most importantly, you cant base your optimization efforts on
feelings its either faster, more scalable (and you understand why) or its not.

After such a tuning session you may end up with a worse configuration than what you have
started with. In fact, more often than not, thats exactly what I would find when a customer would
first contact me.

Why 17 Config Variables


So I decided go through all of the MySQL 5.1-5.7 settings and distill the ones that, as I have
discovered during these 9 years, really matter for MySQL performance. Based both on my
experience, benchmarks and, most importantly, real life tests with our customers systems. Heres
what I found:

When it comes to MySQL Performance, theres only 17 config file settings you should be
looking at. And, you can easily determine the correct values for most of them!

Please make sure to get yourself familiar with all of these variables, because some of them are
related and cant be tuned in isolation. Also before you change anything, read the First things first
section below where I discuss what you should be wary of when working with MySQL
configuration.

First Things First


Before we get to the list, heres a few things you should keep in mind when working with MySQL
configuration. These are the basic principles and most common mistakes I see being made:
1. Never trust the first response you found on Google (even if thats this blog post) and never do
quick reckless changes. Understand exactly what you are changing. I will try to be verbose in this
blog post, but feel free to look for more resources so you really understand what you are doing.

2. Dont get obsessed about fine-tuning the configuration usually 10-15 variables will give you
the most impact (you will find all of them here), and fine-tuning the variables is highly unlikely to
have any additional benefits. It can do harm though. If you still have a performance problem even
after you have applied all the recommendations (and gotten rid of everything that you shouldnt
have touched in the first place), the problem is probably somewhere else bad queries, lack of
resources, etc.

3. Change one thing at a time. Especially if you already have a solid configuration. If its a new
setup, or you were running with default configuration until now, feel free to go wild and implement
all of these changes at once. Otherwise, change one thing and take some time to monitor the server
after the change.

4. Dont forget to update my.cnf if you made the changes online. You can change a lot of things
online these days, in MySQL 5.7 you can even modify innodb buffer pool size online. But if you
take that route, make sure you also update my.cnf or you will lose all the changes when MySQL is
restarted.

5. Avoid duplicate entries. If you use the same variable twice, MySQL will not complain about it.
It will just use the last value, so be sure you dont add the same variable twice, otherwise you may
end up changing the wrong variable (and not seeing an impact). Also note that a dash - and an
underscore _ can be used interchangeably, so innodb-log-file-size and innodb_log_file_size
are both referring to the same server setting.

6. Dont just double the size of all buffers. Some buffers are local, some global. Some are storage
engine related, some are server wide. So if you have just added twice more memory to the server,
check every variable you want to change before changing it and see if it makes sense to do so. Oh
and if its not mentioned in this list below, most likely you dont need to change it anyway.

7. Use the right section [mysqld]. MySQL configuration file can have many sessions, such as
[mysql], [client], [mysqld_safe] and so on. When tuning MySQL server, make sure you are working
with the [mysqld] section, or your changes will have no impact. The only exception here is if youre
using the mysqld_multi script, in which case youll be working with several sections at once.

The 17 Key MySQL Variables


FYI, I have prepared a special my.cnf file that includes all of these 17 variables with short
explanations and links back to appropriate sections with more verbose explanations. You will be
able to download it below.

And now lets get down to business. Heres the list of key MySQL variables you should be tuning
to get the best performance out of your MySQL server:

1. default_storage_engine choose the right engine

If youre already on MySQL 5.6 or 5.7 and all of your tables are InnoDB, youre all set. If not,
make sure you switch to InnoDB and set default_storage_engine to InnoDB.
Why? In a nutshell, because InnoDB is the best MySQL (and Percona Server, and MariaDB)
storage engine it supports transactions, high concurrency, has an amazing performance (when
configured properly). And heres the long format version of why.

If you do not agree that InnoDB is the way to go, stop right there. Do not read any further. Your
eyes will bleed!

2. innodb_buffer_pool_size get the best out of your memory

This is the most important InnoDB variable. Actually, if youre using InnoDB as your main storage
engine, for you its THE most important variable for the entire MySQL. In fact, its so important I
have created a separate page just for innodb buffer pool size.

Essentially, innodb_buffer_pool_size specifies how much memory MySQL should allocate for
InnoDB buffer pool, and InnoDB buffer pool is where InnoDB keeps cached data, secondary
indexes, dirty data (data thats been modified, but not yet written to disk) and various internal
structures such as Adaptive Hash Index.

As a rule of thumb, on a dedicated MySQL server you want to set it to 80% of total server memory.
If you run a shared server, or if you wonder whether your innodb buffer pool is sized properly, see
here for details.

3. innodb_log_file_size room for MySQLs redo log

This sets the size of the InnoDBs redo log files which, in MySQL world, are often called simply
transaction logs. And right until MySQL 5.6.8 the default value of innodb_log_file_size=5M was
the single biggest InnoDB performance killer. Starting with MySQL 5.6.8, the default was raised to
48M which, for many intensive systems, is still way too low.

As a rule of thumb you should set this to accommodate ~1-2h worth of writes and if youre in a
hurry, having this set to 1-2G will give you pretty good performance with pretty much any
workload. However, because this is so important, I have created a special page for this variable as
well click here to learn more about MySQLs redo logging and how to fine-tune the
innodb_log_file_size.

Oh and before we go to the next variable, let me mention innodb_log_buffer_size real quick.
Mention because it is often not well understood and as a consequence over-appreciated. The
reality is that most of the time you will only be using a small fraction of this buffer enough to hold
the changes of your tiny transactions before they are committed and changes are written to disk.

Of course, if you have large transactions that do lots of changes, then yes, it may make sense to
have a larger than default innodb log buffer size, but if youre using autocommit or if your
transactions make no more than few kilobytes of changes, stay with the default
innodb_log_buffer_size.

4. innodb_flush_log_at_trx_commit durable or not? That is the question!

By default, innodb_flush_log_at_trx_commit is set to 1 which instructs InnoDB to flush AND


sync after EVERY transaction commit. And if you are using autocommit, then every single
INSERT, UPDATE or DELETE statement is a transaction commit.
Sync is an expensive operation (especially when you dont have a write-back cache) as it involves
the actual synchronous physical write to the disk, so whenever possible, I would recommend to
avoid using this default configuration.

Two alternative values for this variable are 0 and 2:

0 means flush to disk, but do not sync (no actual IO is performed on commit),
2 means dont flush and dont sync (again no actual IO is performed on commit).

So if you have it set to 0 or 2, sync is performed once a second instead. And the obvious
disadvantage is that you may lose last second worth of committed data. Yes, you read that right
those transactions would have committed, but if server loses power, those changes never happened.

Obviously, for financial institutions such as banks its a huge no-go. Most websites, however, can
(and do) run with innodb_flush_log_at_trx_commit=0|2 and have no issues even if the server
crashes eventually. After all, just few years ago many websites were using MyISAM, which will
lose up to 30s worth of written data in case of a crash. (not to mention the crazy slow table repair
process).

Finally, whats the practical difference between 0 and 2? Well, performance wise the difference is
negligible really, because a flush to OS cache is cheap (read fast). So it kind of makes sense to have
it set to 0, in which case if MySQL (but not the whole machine) crashes, you do NOT lose any data
as it will be in OS cache and synced to disk from there eventually.

BTW, if you prefer durability to performance and have innodb_flush_log_at_trx_commit set to 1,


let me draw your attention to the next variable which is closely related:

5. sync_binlog thats for durable binlog

Tens of pages have been written about sync_binlog and its relationship with
innodb_flush_log_at_trx_commit, but let me simplify it for you for now:

a) If your MySQL server has no slaves and you dont do backups, set sync_binlog=0 and be happy
with a good performance
b) If you do have slaves and you do backups, but you dont mind losing a few events from the
binary logs in case of a master crash, you may still want to use sync_binlog=0 for the sake of a
better performance.
c) If you do have slaves and/or backups, and you do care about slaves consistency and/or point in
time recovery (ability to restore your database to a specific point in time by using your latest
consistent backup and binary logs) and you are also running
innodb_flush_log_at_trx_commit=1, then you should seriously consider using sync_binlog=1.

Problem is of course that sync_binlog=1 has a pretty significant price now every single
transaction is again synced to disk to the binary logs. Youd think why not do both sync
operations at once, and youd be right new versions of MySQL (both 5.6 and 5.7, MariaDB and
Percona Server) already have a properly working group commit, in which case the price for this
sync_binlog=1 is not that big, but older versions of MySQL have a really significant performance
penalty, so be careful with that and watch your disk writes.

So far so good? Good. Next.


6. innodb_flush_method your chance to avoid double buffering

Set innodb_flush_method to O_DIRECT to avoid double-buffering. The only case you should NOT
use O_DIRECT is when it is not supported by your operating system. But if youre on Linux, use
O_DIRECT to enable direct IO.

Without direct IO, double-buffering happens because all database changes are first written to OS
cache and then synced to disk so you end up with the same data in InnoDB buffer pool AND in
OS cache. Yes, that means in a write-intensive environment you could be losing up to almost 50%
of memory, especially if your buffer pool is capped at 50% of total memory. And if not, server
could end up swapping due to high pressure on the OS cache.

In other words, do set innodb_flush_method=O_DIRECT.

7. innodb_buffer_pool_instances reduce global mutex contention

MySQL 5.5 introduced buffer pool instances as a means to reduce internal locking contention and
improve MySQL scalability. In version 5.5 this was known to improve the throughput to some
degree only, however MySQL 5.6 was a big step up, so while in MySQL 5.5 you may want to be
more conservative and have innodb_buffer_pool_instances=4, on MySQL 5.6 and 5.7 you may
go with 8-16 buffer pool instances.

Your mileage may vary of course, but with most workloads, that should give you best results.

Oh and obviously do not expect this to make any difference to a single query response time. The
difference will only show with highly concurrent workloads i.e. those with many threads doing
many things in MySQL at the same time.

8. innodb_thread_concurrency have better control over your threads

You may hear very often that you should just set innodb_thread_concurrency=0 and forget it.
Well, thats only true if you have a light or moderate workload. However, if youre approaching the
saturation point of your CPU or IO subsystem, and especially if you have occasional spikes when
the system needs to operate properly when overloaded, then I would highly recommend to tackle
innodb_thread_concurrency.

Heres the thing InnoDB has a way to control how many threads are executing in parallel lets
call it a concurrency control mechanism. And for the most part it is controlled by
innodb_thread_concurrency. If you set it to zero, concurrency control is off, therefore InnoDB
will be processing all requests immediately as they come in (and as many as it needs to).

This is fine if you have 32 CPU cores and 4 requests. But imagine you have 4 CPU cores and 32
requests if you let the 32 requests run in parallel, youre asking for trouble. Because these 32
requests will only have 4 CPU cores, they will obviously be at least 8 times slower than usually (in
reality, more than 8 times slower of course), but each of those requests will have its own external
and internal locks which leaves great opportunities for all the queries to pile up.

OK, not to overwhelm you right now, Ill stop there and I will only mention that theres two other
variables innodb_thread_sleep_delay and innodb_concurrency_tickets that will help you
take control over concurrency. I will write all about how this concurrency control mechanism works
in a few weeks and in the meantime, I invite you to do some experimentation with
innodb_thread_concurrency, after all you can change it online by simply running the following
command:

1 SET global innodb_thread_concurrency=X;


For most workloads and servers, 8 is a good start and then you should only increase it gradually if
you see that the server keeps hitting that limit while hardware is under-utilised. To see where the
Threads stand at any given moment, run show engine innodb status\G and look for a similar
line in the ROW OPERATIONS section:

1 22 queries inside InnoDB, 104 queries in queue

9. skip_name_resolve do skip that reverse IP lookup

This is a funny one, but I couldnt not mention it as its still quite common to see it not being used.
Essentially, you want to add skip_name_resolve to avoid DNS resolution on connection.

Most of the time you will feel no impact when you change this, because most of the time DNS
servers work pretty fast (and they also cache results). But when a DNS server will fail, it will be
such a PITA to figure out what are those unauthenticated connections doing on your server and
why things all of the sudden seem slow

So. Dont wait until this happens to you. Add this variable now and get rid of any hostname based
grants. The only exception here is if youre using hosts file based name resolution. Or if your DNS
servers will never fail (ha ha).

10. innodb_io_capacity, innodb_io_capacity_max cap InnoDB IO usage

These two variables deserve a special article just for them (and they will get one), but for now, let
me brief you in:

innodb_io_capacity controls how many write IO requests per second (IOPS) will MySQL
do when flushing the dirty data,
innodb_io_capacity_max controls how many write IOPS will MySQL do flushing the
dirty data when its under stress.

So, first of all, this has nothing to do with foreground reads ones performed by SELECT queries.
For reads, MySQL will do the maximum number of IOPS possible to return the result as soon as
possible. As for writes, MySQL has background flushing cycles and during each cycle it checks
how much data needs to be flushed and it will use no more than innodb_io_capacity IOPS to do
the flushing. That also includes change buffer merges (change buffer is a where secondary keys
dirty pages are stored until they are flushed to disk).

Second, I need to clarify what under stress means. This, what MySQL calls an emergency, is a
situation when MySQL is behind with flushing and it needs to flush some data in order to allow for
new writes to come in. Then, MySQL will use the innodb_io_capacity_max amount of IOPS.

Now heres the $100 question: so what do you set the innodb_io_capacity and
innodb_io_capacity_max to?
Best solution measure random write throughput of your storage and set
innodb_io_capacity_max to the maximum you could achieve, and innodb_io_capacity to 50-
75% of it, especially if your system is write-intensive.

Often you can predict how many IOPS your system can do, especially if it has magnetic drives. For
example, 8 15k disks in RAID10 can do about 1000 random write IOPS, so you could have
innodb_io_capacity=600 and innodb_io_capacity_max=1000. Many cheap enterprise SSDs
can do 4,000-10,000 IOPS etc.

Nothing bad will happen if you dont make it perfect. But. Beware that the default values of 200
and 400 respectively could be limiting your write throughput and consequently you may have
occasional stalls for the flushing activity to catch up. If thats the case you could be either
saturating your disks, or you dont have a high enough values for these variables.

11. innodb_stats_on_metadata turn them OFF!

If youre running MySQL 5.6 or 5.7 and you didnt change the default
innodb_stats_on_metadata value, youre all set.

On MySQL 5.5 or 5.1, however, I highly recommend to turn this OFF that way commands like
show table status and queries against INFORMATION_SCHEMA will be instantaneous instead of
taking seconds to run and causing additional IO.

My former colleague Stephane Combaudon from Percona has written a very good blog post on this.

Oh and note that starting with 5.1.32, this is a dynamic variable, so you dont need to restart
MySQL just to disable that.

12. innodb_buffer_pool_dump_at_shutdown & innodb_buffer_pool_load_at_startup

It may seem the two variables innodb_buffer_pool_dump_at_shutdown and


innodb_buffer_pool_load_at_startup are not performance related, but if you are occasionally
restarting your MySQL server (e.g. to apply configuration changes), they are. When both are enabled,
the contents of MySQL buffer pool (more specifically, cached pages) are stored into a file upon
shutdown. And when you start MySQL, it starts a background thread that loads back the contents of
buffer pool and improves the warm-up speed that way up to 3-5 times.

Couple of things:

First, it doesnt actually copy the contents of the buffer pool into a file upon shutdown, it merely
copies the tablespace IDs and page IDs enough information to locate the page on disk. Then, it can
load those pages really fast with large sequential reads instead of hundreds of thousands of small
random reads.

Second, loading of the contents on startup happens in the background, hence MySQL doesnt wait
until the buffer pool contents are loaded and starts serving requests immediately (so its not as
intrusive as it may seem).

Third (I know, I know, three isnt really a couple anymore), starting with MySQL 5.7.7, only 25% of
least recently used buffer pool pages are dumped on shutdown, but you have total control over that
use innodb_buffer_pool_dump_pct to control how many pages (expressed in percents) would you
like to be dumped (and restored). I vote 75-100.
And fourth (sorry!), while MySQL only supports this since MySQL 5.6, in Percona Server, you had
this for quite a while now so if you want to stay on version 5.1 or 5.5, check this out (version 5.1
link).

13. innodb_adaptive_hash_index_parts split the AHI mutex

If youre running a lot of SELECT queries (and everything else is perfectly in tune), then Adaptive
Hash Index is going to be your next bottle-neck. Adaptive Hash Indexes are dynamic indexes
maintained internally by InnoDB that improve performance for your most commonly used query
patterns. This feature can be turned off with a server restart, but by default it is ON in all versions of
MySQL.

While its quite a complex technology (more on it here), in most cases it gives a nice boost to many
types of queries. That is, until you have too many queries hitting the database, at which point they
start spending too much time waiting on the AHI locks and latches.

If youre on MySQL 5.7, you wont have any issues with that
innodb_adaptive_hash_index_parts is there and its set to 8 by default, so the adaptive hash index
is split into 8 partitions, therefore theres no global mutex and youre good to go.

All MySQL versions before 5.7, unfortunately, have no control over the number of AHI partitions.
In other words, theres one global mutex protecting the AHI and with many select queries youre
constantly hitting this wall.

So if youre running 5.1 or 5.6, and you have thousands of select queries per second, the easiest
solution would be to switch to same version of Percona Server and enable AHI partitions. The variable
in Percona Server is called innodb_adaptive_hash_index_partitions.

14. query_cache_type ON? OFF? ON DEMAND?

A lot of people think Query cache is great and you should definitely use it. Well, sometimes its true
sometimes it is useful. But its only useful when you have a relatively light workload and especially
if the workload is pretty much read-only with very few or virtually no writes.

If thats your workload, set query_cache_type=ON and query_cache_size=256M and youre done.
Note, however, you should never set the query cache size any higher, or you will run into serious
server stalls due to query cache invalidation. Ive seen this too many times and until someone figures
out a way to split a global query cache mutex, this will not go away.

Now if you have an intensive workload, then I would recommended this query cache size tuner
written by one of MySQL community leaders Domas Mituzas.

More seriously though, you should not only set the query_cache_size=0 but also its very important
that you set query_cache_type=OFF and restart the server when you do that this way MySQL will
stop using query cache mutex for all queries even those that wouldnt use the query cache anyway.

So if youre still using the query cache and you shouldnt, make these changes now or you will suffer!

15. innodb_checksum_algorithm the secret hardware acceleration trick


Most mainstream CPUs nowadays support native crc32 instructions and MySQL can finally make
use of that to improve the speed of calculating the InnoDB checksums significantly. Heres the two
variables you should enable to make use of that:

1. innodb_checksum_algorithm=crc32 (available since MySQL 5.6)


2. innodb_log_checksum_algorithm=crc32 (available since MySQL 5.7)

Starting with MySQL 5.7.7, innodb_checksum_algorithm=crc32 is set by default, and now,


starting with MySQL 5.7.9 GA, innodb_log_checksum_algorithm is no longer available, instead
innodb_log_checksums was introduced which is ON by default, so you dont need to do anything
here.

In MySQL 5.6, however, you only have innodb_checksum_algorithm option, but do set it to crc32
to enable hardware acceleration for page checksums.

Checksums are calculated every single time a page (or log entry) is read or written, so this is definitely
YUUGE! (right, Donald?)

Oh and BTW, this is totally safe to change on a server that already has tables created with checksum
type innodb. In fact, you can change it dynamically, online, while the server is running (There, I
said it three times, now its completely redundant).

16. table_open_cache_instances its there for a reason

Starting with MySQL 5.6.6, table cache can be split into multiple partitions and if youre running
MySQL 5.6 or newer, definitely do that.

Table cache is where the list of currently opened tables is stored and the mutex is locked whenever a
table is opened or closed (and, in fact, in a number of other cases) even if thats an implicit
temporary table. And using multiple partitions definitely reduces potential contention here. Ive seen
this LOCK_open mutex issue in the wild too many times.

Starting with MySQL 5.7.8, table_open_cache_instances=16 is the default configuration, and Id


say it is definitely a good starting point both on MySQL 5.6 and 5.7.

17. innodb_read_io_threads & innodb_write_io_threads last and, yes, least

Ive placed this last because its really not as important as it may seem.

First of all, your MySQL is likely already using Asynchronous IO (AIO) which on Linux is supported
since MySQL 5.5. Second, both innodb_read_io_threads and innodb_write_io_threads are
only used for the background activity, such as checkpointing (flushing dirty pages to disk), change
buffer merge operations and, sometimes, read-ahead activity.

So, while its not a key variable to tune, aligning it to the number of bearing disks is still a good idea.
So for example on RAID10 with 8 disks, you may want to have innodb_read_io_threads=8 and
innodb_write_io_threads=4. If you have an SSD, well then just have it around 16-32, but do not
expect much performance difference, unless your server is extremely write-heavy and disk IO is the
bottle-neck.

And were done.


I wanted to make all these configuration variables as accessible as possible, so I made a special my.cnf
with my recommended configuration (and useful comments that will help you fine-tune it for your
tastes). If youd like to get that file and also receive a nice eBook with these 17 variables discussed
in depth (once its done), leave your email address in the form below.

Final thoughts
Its quite amazing how much you can improve things with small changes over the vanilla MySQL
configuration. But you wanna know the real truth? The truth is we havent even started!

While improving MySQL configuration can actually impact its performance greatly, you must have
queries that are already tuned almost to perfection for that to be the case. And most of the time I find
that thats exactly where the problem lies in the queries.

Stay tuned and I will show you exactly the process we were using at Percona to identify which queries
need to be fixed find the ones that are occasionally (or constantly) slow and also the ones that impact
the server utilisation the most. The easiest way for us to stay in touch is over the email, so if youd
like to hear from me on that and also if youd like to receive the special my.cnf file I mentioned (with
my recommended configuration, and useful comments that will help you fine-tune it for your tastes),
please leave your email address in the form below.