SlideShare a Scribd company logo
MYSQL PERFORMANCE
OPTIMIZATION
(MYSQL PRESTATIE-OPTIMALISATIE)
ALS JE DIT MOEST LEZEN, DAN BEN JE IN DE VERKEERDE KAMER… 
JOOMLADAY NETHERLANDS 2013
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 1
INTRODUCTION
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
INTRODUCTION
• Eli Aschkenasy
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
INTRODUCTION
• Eli Aschkenasy
• themodularway.com
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
INTRODUCTION
• Eli Aschkenasy
• themodularway.com
• Oracle certified (doesn’t really mean anything)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
INTRODUCTION
• Eli Aschkenasy
• themodularway.com
• Oracle certified (doesn’t really mean anything)
• GE sourcing database project
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
INTRODUCTION
• Eli Aschkenasy
• themodularway.com
• Oracle certified (doesn’t really mean anything)
• GE sourcing database project
• Agenda
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
AGENDA
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
AGENDA
• Introduction (5min)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
AGENDA
• Introduction (5min)
• Strategic Overview (5min)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
AGENDA
• Introduction (5min)
• Strategic Overview (5min)
• Design Considerations – Schema Optimization – Strategic (10min)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
AGENDA
• Introduction (5min)
• Strategic Overview (5min)
• Design Considerations – Schema Optimization – Strategic (10min)
• Design Considerations – Schema Optimization – Normalization
(10min hopefully)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
AGENDA
• Introduction (5min)
• Strategic Overview (5min)
• Design Considerations – Schema Optimization – Strategic (10min)
• Design Considerations – Schema Optimization – Normalization
(10min hopefully)
• Indexing (5min)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
AGENDA
• Introduction (5min)
• Strategic Overview (5min)
• Design Considerations – Schema Optimization – Strategic (10min)
• Design Considerations – Schema Optimization – Normalization
(10min hopefully)
• Indexing (5min)
• Query Optimization (10min)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
STRATEGIC OVERVIEW
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
STRATEGIC OVERVIEW
• Find smart people – Learn from them
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
STRATEGIC OVERVIEW
• Find smart people – Learn from them
• Find less knowledgeable people – Teach them (great design
benefits)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
STRATEGIC OVERVIEW
• Find smart people – Learn from them
• Find less knowledgeable people – Teach them (great design benefits)
• Talk to the business people! – Become their marketing specialist
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
STRATEGIC OVERVIEW
• Find smart people – Learn from them
• Find less knowledgeable people – Teach them (great design benefits)
• Talk to the business people! – Become their marketing specialist
• Benchmark – Do It !!!!!!!!!!
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
STRATEGIC OVERVIEW
• Find smart people – Learn from them
• Find less knowledgeable people – Teach them (great design benefits)
• Talk to the business people! – Become their marketing specialist
• Benchmark – Do It !!!!!!!!!!
• Decide early
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
AGENDA
• Introduction (5min)
• Strategic Overview (5min)
• Design Considerations – Schema Optimization – Strategic (10min)
• Design Considerations – Schema Optimization – Normalization
(10min hopefully)
• Indexing (5min)
• Query Optimization (10min)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 5
DESIGN CONSIDERATIONS
SCHEMA OPTIMIZATION – STRATEGIC
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 6
DESIGN CONSIDERATIONS
SCHEMA OPTIMIZATION – STRATEGIC
• DB Engines (InnoDB vs. MyISAM) – not including MySQL 5.6
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 6
InnoDB
• Transactional
• Hot (Online) Backup
• Crash Safe(er)
MyISAM
• Full-Text Indexing
• Compression
• Low(er) Space Consumption
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 7
InnoDB
• Transactional
• Hot (Online) Backup
• Crash Safe(er)
MyISAM
• Full-Text Indexing
• Compression
• Low(er) Space Consumption
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 7
• Always!
• Transactional
InnoDB
• Transactional
• Hot (Online) Backup
• Crash Safe(er)
MyISAM
• Full-Text Indexing
• Compression
• Low(er) Space Consumption
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 7
• Always!
• Transactional
• Logging
• Read Only
DESIGN CONSIDERATIONS
SCHEMA OPTIMIZATION – STRATEGIC
• DB Engines (InnoDB vs. MyISAM) – not including MySQL 5.6
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 8
DESIGN CONSIDERATIONS
SCHEMA OPTIMIZATION – STRATEGIC
• DB Engines (InnoDB vs. MyISAM) – not including MySQL 5.6
• Data Types (Numbers, Strings, Special)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 8
NUMBERS STRINGS SPECIAL
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 9
NUMBERS
INT(1) vs. INT(20) ? (trick question)
UNSIGNED vs. SIGNED
FLOAT isn’t accurate but fast
DECIMAL in MySQL<4.1 calculated
as FLOAT
DECIMAL needs additional byte to
store decimal point
Think if BIGINT could be used even
for precise calculations
(x*1’000’000)
PLEASE, PLEASE, use unsigned
integer as primary index. (we’ll
talk about it later again).
STRINGS SPECIAL
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 9
NUMBERS
INT(1) vs. INT(20) ? (trick question)
UNSIGNED vs. SIGNED
FLOAT isn’t accurate but fast
DECIMAL in MySQL<4.1 calculated
as FLOAT
DECIMAL needs additional byte to
store decimal point
Think if BIGINT could be used even
for precise calculations
(x*1’000’000)
PLEASE, PLEASE, use unsigned
integer as primary index. (we’ll
talk about it later again).
STRINGS
Use CHAR for fixed length columns
US States is the best example
State code are perfect for
TINYINT UNSIGNED
MD5 Hash values are
another good candidate for
CHAR usage
VARCHAR requires length byte!
VARCHAR allocates space in chunks
so don’t be overly generous
TEXT is problematic in SORTs
Trick: Use SUBSTRING(x, fixed) to
alleviate the problem
SPECIAL
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 9
NUMBERS
INT(1) vs. INT(20) ? (trick question)
UNSIGNED vs. SIGNED
FLOAT isn’t accurate but fast
DECIMAL in MySQL<4.1 calculated
as FLOAT
DECIMAL needs additional byte to
store decimal point
Think if BIGINT could be used even
for precise calculations
(x*1’000’000)
PLEASE, PLEASE, use unsigned
integer as primary index. (we’ll
talk about it later again).
STRINGS
Use CHAR for fixed length columns
US States is the best example
State code are perfect for
TINYINT UNSIGNED
MD5 Hash values are
another good candidate for
CHAR usage
VARCHAR requires length byte!
VARCHAR allocates space in chunks
so don’t be overly generous
TEXT is problematic in SORTs
Trick: Use SUBSTRING(x, fixed) to
alleviate the problem
SPECIAL
Avoid NULL if possible
Harder for MySQL to
optimize query
Use TIMESTAMP instead of DATETIME
Limit 2038
EST
TIMESTAMP uses less
space
(I hardly ever use TIMESTAMP…)
BIT (actually string form)
Don’t use ENUM or SET
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 9
CODE EXAMPLES - BIT
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 10
mysql> CREATE TABLE bittest(a bit(8));
mysql> INSERT INTO bittest VALUES(b'00111001');
mysql> SELECT a, a + 0 FROM bittest;
+------+-------+
| a | a + 0 |
+------+-------+
| 9 | 57 |
+------+-------+
CODE EXAMPLES - ENUM
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 11
mysql> CREATE TABLE enum_test(e ENUM('fish', 'apple', 'dog') NOT NULL);
mysql> INSERT INTO enum_test(e) VALUES('fish'), ('dog'), ('apple');
mysql> SELECT e + 0 FROM enum_test; mysql> SELECT e FROM enum_test ORDER
BY e;
+-------+
| e + 0 |
+-------+
| 1 |
| 3 |
| 2 |
+-------+
CODE EXAMPLES - ENUM
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 11
mysql> CREATE TABLE enum_test(e ENUM('fish', 'apple', 'dog') NOT NULL);
mysql> INSERT INTO enum_test(e) VALUES('fish'), ('dog'), ('apple');
mysql> SELECT e + 0 FROM enum_test; mysql> SELECT e FROM enum_test ORDER
BY e;
+-------+
| e + 0 |
+-------+
| 1 |
| 3 |
| 2 |
+-------+
+-------+
| e |
+-------+
| fish |
| apple |
| dog |
+-------+
CODE EXAMPLES – DATETIME NOT NULL
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 12
DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00‘
AGENDA
• Introduction (5min)
• Strategic Overview (5min)
• Design Considerations – Schema Optimization – Strategic (10min)
• Design Considerations – Schema Optimization – Normalization
(10min hopefully)
• Indexing (5min)
• Query Optimization (10min)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 13
DESIGN CONSIDERATIONS
SCHEMA OPTIMIZATION – NORMALIZATION
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 14
DESIGN CONSIDERATIONS
SCHEMA OPTIMIZATION – NORMALIZATION
• Normalized data is non-redundant
(Text book says this is the best option)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 14
DESIGN CONSIDERATIONS
SCHEMA OPTIMIZATION – NORMALIZATION
• Normalized data is non-redundant
(Text book says this is the best option)
• Reality introduces de-normalization
Welcome to Summary and Cache Tables
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 14
CODE EXAMPLES – SUMMARY TABLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 15
mysql> CREATE TABLE msg_per_hr (
hr DATETIME NOT NULL,
cnt INT UNSIGNED NOT NULL,
PRIMARY KEY(hr)
);
mysql> SELECT SUM(cnt) FROM msg_per_hr stored 23
hour
WHERE hr BETWEEN CONCAT(LEFT(NOW(), 14), '00:00') - INTERVAL 23 HOUR concat rounds
to nearest hr.
AND CONCAT(LEFT(NOW(), 14), '00:00') - INTERVAL 1 HOUR;
mysql> SELECT COUNT(*) FROM message first hour
WHERE posted >= NOW() - INTERVAL 24 HOUR
AND posted < CONCAT(LEFT(NOW(), 14), '00:00') - INTERVAL 23 HOUR;
mysql> SELECT COUNT(*) FROM message last hour
WHERE posted >= CONCAT(LEFT(NOW(), 14), '00:00');
CODE EXAMPLES – CACHE TABLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 16
mysql> DROP TABLE IF EXISTS my_cache_new, my_cache_old;
mysql> CREATE TABLE my_cache_new LIKE my_cache;
-- populate my_cache_new as desired
mysql> RENAME TABLE my_cache TO my_cache_old, my_cache_new TO my_cache;
CODE EXAMPLES – COUNTER TABLE
CONCURRENCY ISSUE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 17
mysql> CREATE TABLE hit_counter (
cnt INT UNSIGNED NOT NULL
) ENGINE=InnoDB;
mysql> UPDATE hit_counter SET cnt = cnt + 1;
mysql> SELECT cnt FROM hit_counter;
CODE EXAMPLES – COUNTER TABLE
CONCURRENCY SOLUTION
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 18
mysql> CREATE TABLE hit_counter (
slot TINYINT UNSIGNED NOT NULL PRIMARY KEY,
cnt INT UNSIGNED NOT NULL
) ENGINE=InnoDB;
mysql> INSERT INTO hit_counter VALUES
(0,0),
(1,0),
(2,0),
(3,0),
…
(99,0);
mysql> UPDATE hit_counter SET cnt = cnt + 1 WHERE slot = RAND() * 100;
mysql> SELECT SUM(cnt) FROM hit_counter;
AGENDA
• Introduction (5min)
• Strategic Overview (5min)
• Design Considerations – Schema Optimization – Strategic (10min)
• Design Considerations – Schema Optimization – Normalization
(10min hopefully)
• Indexing (5min)
• Query Optimization (10min)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 19
INDEXING
HASH INDEX
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 20
INDEXING
HASH INDEX
• InnoDB creates adaptive hash indexes on frequent queries
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 20
INDEXING
HASH INDEX
• InnoDB creates adaptive hash indexes on frequent queries
• Main downside is that index doesn’t help sorting
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 20
INDEXING
HASH INDEX
• InnoDB creates adaptive hash indexes on frequent queries
• Main downside is that index doesn’t help sorting
• Hash indexes can’t speed up range queries (WHERE age > 18)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 20
INDEXING
HASH INDEX – HOW TO – INCLUDING HASH
COLLISION
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 21
mysql> SELECT id FROM url WHERE url="http://www.joomladagen.nl";
CREATE TABLE pseudohash (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
url VARCHAR(255) NOT NULL,
url_crc INT UNSIGNED NOT NULL DEFAULT 0,
PRIMARY KEY(id)
);
CREATE TRIGGER pseudohash_crc_ins BEFORE INSERT ON pseudohash FOR EACH ROW BEGIN
SET NEW.url_crc=crc32(NEW.url);
CREATE TRIGGER pseudohash_crc_upd BEFORE UPDATE ON pseudohash FOR EACH ROW BEGIN
SET NEW.url_crc=crc32(NEW.url);
mysql> SELECT id FROM url WHERE url_crc=CRC32("http://www.joomladagen.nl") AND
url="http://www.joomladagen.nl";
INDEXING
INDEX PROBLEMS
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 22
SELECT * FROM Orgchart SELECT a, c FROM Orgchart SELECT a, c FROM Orgchart
WHERE lft - rgt = 1; WHERE lft - rgt = 1; WHERE lft =(rgt – 1);
SELECT name FROM people mysql> ALTER TABLE people ADD KEY (idx_name(6));
WHERE name = ‘Hans’;
CREATE TABLE t ( KEY(c1,c2,c3) ? KEY(c1,c3) Specificity!
c1 INT,
c2 INT,
c3 INT,
KEY(c1),
KEY(c2),
KEY(c3)
);
INDEXING
INDEX PROBLEMS
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 22
SELECT * FROM Orgchart SELECT a, c FROM Orgchart SELECT a, c FROM Orgchart
WHERE lft - rgt = 1; WHERE lft - rgt = 1; WHERE lft =(rgt – 1);
SELECT name FROM people mysql> ALTER TABLE people ADD KEY (idx_name(6));
WHERE name = ‘Hans’;
CREATE TABLE t ( KEY(c1,c2,c3) ? KEY(c1,c3) Specificity!
c1 INT,
c2 INT,
c3 INT,
KEY(c1),
KEY(c2),
KEY(c3)
);
SELECT cc FROM payment WHERE staff_id = 2 AND customer_id =
584;
INDEXING
INDEX PROBLEMS
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 22
SELECT * FROM Orgchart SELECT a, c FROM Orgchart SELECT a, c FROM Orgchart
WHERE lft - rgt = 1; WHERE lft - rgt = 1; WHERE lft =(rgt – 1);
SELECT name FROM people mysql> ALTER TABLE people ADD KEY (idx_name(6));
WHERE name = ‘Hans’;
CREATE TABLE t ( KEY(c1,c2,c3) ? KEY(c1,c3) Specificity!
c1 INT,
c2 INT,
c3 INT,
KEY(c1),
KEY(c2),
KEY(c3)
);
SELECT cc FROM payment WHERE staff_id = 2 AND customer_id =
584;
KEY(staff_id,customer_id) ?
INDEXING
INDEX PROBLEMS
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 22
SELECT * FROM Orgchart SELECT a, c FROM Orgchart SELECT a, c FROM Orgchart
WHERE lft - rgt = 1; WHERE lft - rgt = 1; WHERE lft =(rgt – 1);
SELECT name FROM people mysql> ALTER TABLE people ADD KEY (idx_name(6));
WHERE name = ‘Hans’;
CREATE TABLE t ( KEY(c1,c2,c3) ? KEY(c1,c3) Specificity!
c1 INT,
c2 INT,
c3 INT,
KEY(c1),
KEY(c2),
KEY(c3)
);
SELECT cc FROM payment WHERE staff_id = 2 AND customer_id =
584;
KEY(staff_id,customer_id) ?
SELECT SUM(staff_id = 2), SUM(customer_id = 584) FROM
paymentG
*************************** 1. row ***************************
SUM(staff_id = 2): 7992
SUM(customer_id = 584): 30
INDEXING
INDEX PROBLEMS
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 22
SELECT * FROM Orgchart SELECT a, c FROM Orgchart SELECT a, c FROM Orgchart
WHERE lft - rgt = 1; WHERE lft - rgt = 1; WHERE lft =(rgt – 1);
SELECT name FROM people mysql> ALTER TABLE people ADD KEY (idx_name(6));
WHERE name = ‘Hans’;
CREATE TABLE t ( KEY(c1,c2,c3) ? KEY(c1,c3) Specificity!
c1 INT,
c2 INT,
c3 INT,
KEY(c1),
KEY(c2),
KEY(c3)
);
SELECT cc FROM payment WHERE staff_id = 2 AND customer_id =
584;
KEY(staff_id,customer_id) ?
SELECT SUM(staff_id = 2), SUM(customer_id = 584) FROM
paymentG
*************************** 1. row ***************************
SUM(staff_id = 2): 7992
SUM(customer_id = 584): 30
ALTER TABLE payment ADD KEY(customer_id, staff_id);
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
WHERE age BETWEEN 18 AND 25
ORDER BY rating ASC
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
WHERE age BETWEEN 18 AND 25
ORDER BY rating ASC
MySQL can’t use added index if
primary index uses range criterion
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
WHERE age BETWEEN 18 AND 25
ORDER BY rating ASC
MySQL can’t use added index if
primary index uses range criterion
KEY(sex, country)
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
WHERE age BETWEEN 18 AND 25
ORDER BY rating ASC
MySQL can’t use added index if
primary index uses range criterion
KEY(sex, country)
NO Selectivity!!!
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
WHERE age BETWEEN 18 AND 25
ORDER BY rating ASC
MySQL can’t use added index if
primary index uses range criterion
KEY(sex, country)
NO Selectivity!!!
KEY(sex, country)
Assumption: all searches will include sex
and most will include country
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
WHERE age BETWEEN 18 AND 25
ORDER BY rating ASC
MySQL can’t use added index if
primary index uses range criterion
KEY(sex, country)
NO Selectivity!!!
KEY(sex, country)
Assumption: all searches will include sex
and most will include country
Trick: AND sex IN('m', 'f')
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 24
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 24
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
(sex, country, age)
(sex, country, region, age)
(sex, country, region, city, age)
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 24
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
(sex, country, age)
(sex, country, region, age)
(sex, country, region, city, age)
Using the IN() trick, we can implement
just the
(sex, country, region, city, age) index.
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 24
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
(sex, country, age)
(sex, country, region, age)
(sex, country, region, city, age)
Using the IN() trick, we can implement
just the
(sex, country, region, city, age) index.
Why is age at end?
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 24
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
(sex, country, age)
(sex, country, region, age)
(sex, country, region, city, age)
Using the IN() trick, we can implement
just the
(sex, country, region, city, age) index.
Why is age at end?
Remember our range problem?
MySQL uses indexes from left to right
unit the first range query
Trick: Convert WHERE age BETWEEN 18 and 25
to
WHERE age IN(18,19,20,21,22,23,24,25)
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 25
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
SELECT age, country, …. , name FROM profiles
WHERE sex=‘F‘
ORDER BY rating
LIMIT 100000, 10;
Retrieving 100’010 rows, discarding
100’000
If data load per row is 15kb calculated data is
18.32Mb and we’re discarding 18.31Mb!
SELECT age, country, …. , name FROM profiles
INNER JOIN (
SELECT id FROM profiles
WHERE x.sex='M‘
ORDER BY rating LIMIT 100000, 10
) AS x
USING(id);
INDEXING
EXAMPLE
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 25
CREATE TABLE profile(
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
sex CHAR(1) NOT NULL,
age TINYINT NOT NULL,
country VARCHAR(255) NOT NULL,
region VARCHAR(255) NOT NULL DEFAULT ‘’,
city VARCHAR(255) NOT NULL DEFAULT ‘’,
color_hair VARCHAR(255) NOT NULL DEFAULT ‘’,
color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’,
name
…
…
rating TINYINT NOT NULL DEFAULT 1,
PRIMARY KEY(id)
);
KEY(sex, rating)
SELECT age, country, …. , name FROM profiles
WHERE sex=‘F‘
ORDER BY rating
LIMIT 100000, 10;
Retrieving 100’010 rows, discarding
100’000
If data load per row is 15kb calculated data is
18.32Mb and we’re discarding 18.31Mb!
SELECT age, country, …. , name FROM profiles
INNER JOIN (
SELECT id FROM profiles
WHERE x.sex='M‘
ORDER BY rating LIMIT 100000, 10
) AS x
USING(id);
AGENDA
• Introduction (5min)
• Strategic Overview (5min)
• Design Considerations – Schema Optimization – Strategic (10min)
• Design Considerations – Schema Optimization – Normalization
(10min hopefully)
• Indexing (5min)
• Query Optimization (10min)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 26
QUERY OPTIMIZATION
TOO MUCH DATA
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27
SELECT * FROM Orgchart
WHERE lft - rgt = 1;
QUERY OPTIMIZATION
TOO MUCH DATA
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27
SELECT * FROM Orgchart
WHERE lft - rgt = 1;
QUERY OPTIMIZATION
TOO MUCH DATA
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27
SELECT * FROM Orgchart
WHERE lft - rgt = 1;
SELECT * FROM recipes.ingredient
INNER JOIN recipes.recipe_ingredient
USING(ingredient_id)
INNER JOIN recipes.recipe USING(recipe_id)
WHERE recipes.recipe.name = ‘Stroopwafel';
QUERY OPTIMIZATION
TOO MUCH DATA
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27
SELECT * FROM Orgchart
WHERE lft - rgt = 1;
SELECT * FROM recipes.ingredient
INNER JOIN recipes.recipe_ingredient
USING(ingredient_id)
INNER JOIN recipes.recipe USING(recipe_id)
WHERE recipes.recipe.name = ‘Stroopwafel';
All I want is the ingredients for a Stroopwafel
This Query returns all columns for all three tables!
QUERY OPTIMIZATION
TOO MUCH DATA
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27
SELECT * FROM Orgchart
WHERE lft - rgt = 1;
SELECT * FROM recipes.ingredient
INNER JOIN recipes.recipe_ingredient
USING(ingredient_id)
INNER JOIN recipes.recipe USING(recipe_id)
WHERE recipes.recipe.name = ‘Stroopwafel';
All I want is the ingredients for a Stroopwafel
This Query returns all columns for all three tables!
SELECT recipes.ingredient.* FROM recipes.ingredient
...
;
QUERY OPTIMIZATION
TOO MUCH DATA
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27
SELECT * FROM Orgchart
WHERE lft - rgt = 1;
SELECT * FROM recipes.ingredient
INNER JOIN recipes.recipe_ingredient
USING(ingredient_id)
INNER JOIN recipes.recipe USING(recipe_id)
WHERE recipes.recipe.name = ‘Stroopwafel';
All I want is the ingredients for a Stroopwafel
This Query returns all columns for all three tables!
SELECT recipes.ingredient.* FROM recipes.ingredient
...
;
QUERY OPTIMIZATION
TOO MUCH DATA
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27
SELECT * FROM Orgchart
WHERE lft - rgt = 1;
SELECT * FROM recipes.ingredient
INNER JOIN recipes.recipe_ingredient
USING(ingredient_id)
INNER JOIN recipes.recipe USING(recipe_id)
WHERE recipes.recipe.name = ‘Stroopwafel';
All I want is the ingredients for a Stroopwafel
This Query returns all columns for all three tables!
SELECT recipes.ingredient.* FROM recipes.ingredient
...
;
SELECT img, name, …, comment FROM
comments
WHERE user_id = 123983;
QUERY OPTIMIZATION
TOO MUCH DATA
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27
SELECT * FROM Orgchart
WHERE lft - rgt = 1;
SELECT * FROM recipes.ingredient
INNER JOIN recipes.recipe_ingredient
USING(ingredient_id)
INNER JOIN recipes.recipe USING(recipe_id)
WHERE recipes.recipe.name = ‘Stroopwafel';
All I want is the ingredients for a Stroopwafel
This Query returns all columns for all three tables!
SELECT recipes.ingredient.* FROM recipes.ingredient
...
;
SELECT img, name, …, comment FROM
comments
WHERE user_id = 123983;
What, did the image and name change
in the last 2microseconds?!?
QUERY OPTIMIZATION
TOO MUCH DATA
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27
SELECT * FROM Orgchart
WHERE lft - rgt = 1;
SELECT * FROM recipes.ingredient
INNER JOIN recipes.recipe_ingredient
USING(ingredient_id)
INNER JOIN recipes.recipe USING(recipe_id)
WHERE recipes.recipe.name = ‘Stroopwafel';
All I want is the ingredients for a Stroopwafel
This Query returns all columns for all three tables!
SELECT recipes.ingredient.* FROM recipes.ingredient
...
;
SELECT img, name, …, comment FROM
comments
WHERE user_id = 123983;
What, did the image and name change
in the last 2microseconds?!?
SELECT img, name, …, FROM comments
WHERE user_id = 123983;
SELECT comment FROM comments
WHERE user_id = 123983;
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 28
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 28
DELETE FROM messages
WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH);
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 28
DELETE FROM messages
WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH);
<?php
…
$rows_affected = 0;
do {
$rows_affected = do_query("
DELETE FROM messages
WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH)
LIMIT 10000
");
} while $rows_affected > 0;
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29
SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag=‘joomladagen';
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29
SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag=‘joomladagen';
SELECT * FROM tag WHERE tag='joomladagen';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904);
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29
SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag=‘joomladagen';
SELECT * FROM tag WHERE tag='joomladagen';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904);
WHY? DENORMALIZED ?!?
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29
SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag=‘joomladagen';
SELECT * FROM tag WHERE tag='joomladagen';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904);
WHY? DENORMALIZED ?!?
• Query cache validation of 3 tables instead of one
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29
SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag=‘joomladagen';
SELECT * FROM tag WHERE tag='joomladagen';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904);
WHY? DENORMALIZED ?!?
• Query cache validation of 3 tables instead of one
• Lock contention (?)
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29
SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag=‘joomladagen';
SELECT * FROM tag WHERE tag='joomladagen';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904);
WHY? DENORMALIZED ?!?
• Query cache validation of 3 tables instead of one
• Lock contention (?)
• Query index lookup of IN() is better than with JOINS
QUERY OPTIMIZATION
DIVIDE AND CONQUER
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29
SELECT * FROM tag
JOIN tag_post ON tag_post.tag_id=tag.id
JOIN post ON tag_post.post_id=post.id
WHERE tag.tag=‘joomladagen';
SELECT * FROM tag WHERE tag='joomladagen';
SELECT * FROM tag_post WHERE tag_id=1234;
SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904);
WHY? DENORMALIZED ?!?
• Query cache validation of 3 tables instead of one
• Lock contention (?)
• Query index lookup of IN() is better than with JOINS
• Potential for application caching
AGENDA
• Introduction (5min)
• Strategic Overview (5min)
• Design Considerations – Schema Optimization – Strategic (10min)
• Design Considerations – Schema Optimization – Normalization
(10min hopefully)
• Indexing (5min)
• Query Optimization (10min)
JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 30

More Related Content

PPTX
10 performance tips we tend to forget
PDF
Mysql query optimization
PDF
Database Design most common pitfalls
PDF
Better sq lqueries
KEY
15 protips for mysql users
ODP
MySQL Performance Optimization
ODP
Beyond php - it's not (just) about the code
PDF
Learn MySQL - Online Guide
10 performance tips we tend to forget
Mysql query optimization
Database Design most common pitfalls
Better sq lqueries
15 protips for mysql users
MySQL Performance Optimization
Beyond php - it's not (just) about the code
Learn MySQL - Online Guide

Similar to MySQL Performance Optimization #JDNL13 (20)

PPTX
7 Database Mistakes YOU Are Making -- Linuxfest Northwest 2019
ODP
Beyond php - it's not (just) about the code
PDF
Performance Tuning Best Practices
PDF
Relational Database Design Bootcamp
PDF
MySQL Performance Optimization
PDF
query optimization
PPTX
MySQL 101
PDF
Quick And Easy Guide To Speeding Up MySQL for web developers
PDF
Beyond php - it's not (just) about the code
PDF
MySQL for beginners
PDF
Perf Tuning Best Practices
PDF
MySQL best practices at Trovit
PDF
Mysql basics1
PPTX
Performance By Design
PPTX
MySQL: Know more about open Source Database
PDF
MySQL Usability Guidelines
ODP
Mysql For Developers
ODP
Beyond php - it's not (just) about the code
PPT
mysql optimization
PPTX
MySQL 8 - UKOUG Techfest Brighton December 2nd, 2019
7 Database Mistakes YOU Are Making -- Linuxfest Northwest 2019
Beyond php - it's not (just) about the code
Performance Tuning Best Practices
Relational Database Design Bootcamp
MySQL Performance Optimization
query optimization
MySQL 101
Quick And Easy Guide To Speeding Up MySQL for web developers
Beyond php - it's not (just) about the code
MySQL for beginners
Perf Tuning Best Practices
MySQL best practices at Trovit
Mysql basics1
Performance By Design
MySQL: Know more about open Source Database
MySQL Usability Guidelines
Mysql For Developers
Beyond php - it's not (just) about the code
mysql optimization
MySQL 8 - UKOUG Techfest Brighton December 2nd, 2019
Ad

Recently uploaded (20)

PDF
System and Network Administraation Chapter 3
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Understanding Forklifts - TECH EHS Solution
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PDF
System and Network Administration Chapter 2
PPTX
L1 - Introduction to python Backend.pptx
PDF
top salesforce developer skills in 2025.pdf
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
PTS Company Brochure 2025 (1).pdf.......
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PDF
Nekopoi APK 2025 free lastest update
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PPTX
history of c programming in notes for students .pptx
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
medical staffing services at VALiNTRY
System and Network Administraation Chapter 3
2025 Textile ERP Trends: SAP, Odoo & Oracle
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
Navsoft: AI-Powered Business Solutions & Custom Software Development
Understanding Forklifts - TECH EHS Solution
Upgrade and Innovation Strategies for SAP ERP Customers
System and Network Administration Chapter 2
L1 - Introduction to python Backend.pptx
top salesforce developer skills in 2025.pdf
Design an Analysis of Algorithms II-SECS-1021-03
PTS Company Brochure 2025 (1).pdf.......
wealthsignaloriginal-com-DS-text-... (1).pdf
Nekopoi APK 2025 free lastest update
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
How to Choose the Right IT Partner for Your Business in Malaysia
history of c programming in notes for students .pptx
VVF-Customer-Presentation2025-Ver1.9.pptx
Wondershare Filmora 15 Crack With Activation Key [2025
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
medical staffing services at VALiNTRY
Ad

MySQL Performance Optimization #JDNL13

  • 1. MYSQL PERFORMANCE OPTIMIZATION (MYSQL PRESTATIE-OPTIMALISATIE) ALS JE DIT MOEST LEZEN, DAN BEN JE IN DE VERKEERDE KAMER…  JOOMLADAY NETHERLANDS 2013 JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 1
  • 2. INTRODUCTION JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
  • 3. INTRODUCTION • Eli Aschkenasy JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
  • 4. INTRODUCTION • Eli Aschkenasy • themodularway.com JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
  • 5. INTRODUCTION • Eli Aschkenasy • themodularway.com • Oracle certified (doesn’t really mean anything) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
  • 6. INTRODUCTION • Eli Aschkenasy • themodularway.com • Oracle certified (doesn’t really mean anything) • GE sourcing database project JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
  • 7. INTRODUCTION • Eli Aschkenasy • themodularway.com • Oracle certified (doesn’t really mean anything) • GE sourcing database project • Agenda JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 2
  • 8. AGENDA JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
  • 9. AGENDA • Introduction (5min) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
  • 10. AGENDA • Introduction (5min) • Strategic Overview (5min) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
  • 11. AGENDA • Introduction (5min) • Strategic Overview (5min) • Design Considerations – Schema Optimization – Strategic (10min) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
  • 12. AGENDA • Introduction (5min) • Strategic Overview (5min) • Design Considerations – Schema Optimization – Strategic (10min) • Design Considerations – Schema Optimization – Normalization (10min hopefully) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
  • 13. AGENDA • Introduction (5min) • Strategic Overview (5min) • Design Considerations – Schema Optimization – Strategic (10min) • Design Considerations – Schema Optimization – Normalization (10min hopefully) • Indexing (5min) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
  • 14. AGENDA • Introduction (5min) • Strategic Overview (5min) • Design Considerations – Schema Optimization – Strategic (10min) • Design Considerations – Schema Optimization – Normalization (10min hopefully) • Indexing (5min) • Query Optimization (10min) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 3
  • 15. STRATEGIC OVERVIEW JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
  • 16. STRATEGIC OVERVIEW • Find smart people – Learn from them JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
  • 17. STRATEGIC OVERVIEW • Find smart people – Learn from them • Find less knowledgeable people – Teach them (great design benefits) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
  • 18. STRATEGIC OVERVIEW • Find smart people – Learn from them • Find less knowledgeable people – Teach them (great design benefits) • Talk to the business people! – Become their marketing specialist JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
  • 19. STRATEGIC OVERVIEW • Find smart people – Learn from them • Find less knowledgeable people – Teach them (great design benefits) • Talk to the business people! – Become their marketing specialist • Benchmark – Do It !!!!!!!!!! JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
  • 20. STRATEGIC OVERVIEW • Find smart people – Learn from them • Find less knowledgeable people – Teach them (great design benefits) • Talk to the business people! – Become their marketing specialist • Benchmark – Do It !!!!!!!!!! • Decide early JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 4
  • 21. AGENDA • Introduction (5min) • Strategic Overview (5min) • Design Considerations – Schema Optimization – Strategic (10min) • Design Considerations – Schema Optimization – Normalization (10min hopefully) • Indexing (5min) • Query Optimization (10min) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 5
  • 22. DESIGN CONSIDERATIONS SCHEMA OPTIMIZATION – STRATEGIC JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 6
  • 23. DESIGN CONSIDERATIONS SCHEMA OPTIMIZATION – STRATEGIC • DB Engines (InnoDB vs. MyISAM) – not including MySQL 5.6 JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 6
  • 24. InnoDB • Transactional • Hot (Online) Backup • Crash Safe(er) MyISAM • Full-Text Indexing • Compression • Low(er) Space Consumption JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 7
  • 25. InnoDB • Transactional • Hot (Online) Backup • Crash Safe(er) MyISAM • Full-Text Indexing • Compression • Low(er) Space Consumption JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 7 • Always! • Transactional
  • 26. InnoDB • Transactional • Hot (Online) Backup • Crash Safe(er) MyISAM • Full-Text Indexing • Compression • Low(er) Space Consumption JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 7 • Always! • Transactional • Logging • Read Only
  • 27. DESIGN CONSIDERATIONS SCHEMA OPTIMIZATION – STRATEGIC • DB Engines (InnoDB vs. MyISAM) – not including MySQL 5.6 JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 8
  • 28. DESIGN CONSIDERATIONS SCHEMA OPTIMIZATION – STRATEGIC • DB Engines (InnoDB vs. MyISAM) – not including MySQL 5.6 • Data Types (Numbers, Strings, Special) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 8
  • 29. NUMBERS STRINGS SPECIAL JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 9
  • 30. NUMBERS INT(1) vs. INT(20) ? (trick question) UNSIGNED vs. SIGNED FLOAT isn’t accurate but fast DECIMAL in MySQL<4.1 calculated as FLOAT DECIMAL needs additional byte to store decimal point Think if BIGINT could be used even for precise calculations (x*1’000’000) PLEASE, PLEASE, use unsigned integer as primary index. (we’ll talk about it later again). STRINGS SPECIAL JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 9
  • 31. NUMBERS INT(1) vs. INT(20) ? (trick question) UNSIGNED vs. SIGNED FLOAT isn’t accurate but fast DECIMAL in MySQL<4.1 calculated as FLOAT DECIMAL needs additional byte to store decimal point Think if BIGINT could be used even for precise calculations (x*1’000’000) PLEASE, PLEASE, use unsigned integer as primary index. (we’ll talk about it later again). STRINGS Use CHAR for fixed length columns US States is the best example State code are perfect for TINYINT UNSIGNED MD5 Hash values are another good candidate for CHAR usage VARCHAR requires length byte! VARCHAR allocates space in chunks so don’t be overly generous TEXT is problematic in SORTs Trick: Use SUBSTRING(x, fixed) to alleviate the problem SPECIAL JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 9
  • 32. NUMBERS INT(1) vs. INT(20) ? (trick question) UNSIGNED vs. SIGNED FLOAT isn’t accurate but fast DECIMAL in MySQL<4.1 calculated as FLOAT DECIMAL needs additional byte to store decimal point Think if BIGINT could be used even for precise calculations (x*1’000’000) PLEASE, PLEASE, use unsigned integer as primary index. (we’ll talk about it later again). STRINGS Use CHAR for fixed length columns US States is the best example State code are perfect for TINYINT UNSIGNED MD5 Hash values are another good candidate for CHAR usage VARCHAR requires length byte! VARCHAR allocates space in chunks so don’t be overly generous TEXT is problematic in SORTs Trick: Use SUBSTRING(x, fixed) to alleviate the problem SPECIAL Avoid NULL if possible Harder for MySQL to optimize query Use TIMESTAMP instead of DATETIME Limit 2038 EST TIMESTAMP uses less space (I hardly ever use TIMESTAMP…) BIT (actually string form) Don’t use ENUM or SET JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 9
  • 33. CODE EXAMPLES - BIT JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 10 mysql> CREATE TABLE bittest(a bit(8)); mysql> INSERT INTO bittest VALUES(b'00111001'); mysql> SELECT a, a + 0 FROM bittest; +------+-------+ | a | a + 0 | +------+-------+ | 9 | 57 | +------+-------+
  • 34. CODE EXAMPLES - ENUM JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 11 mysql> CREATE TABLE enum_test(e ENUM('fish', 'apple', 'dog') NOT NULL); mysql> INSERT INTO enum_test(e) VALUES('fish'), ('dog'), ('apple'); mysql> SELECT e + 0 FROM enum_test; mysql> SELECT e FROM enum_test ORDER BY e; +-------+ | e + 0 | +-------+ | 1 | | 3 | | 2 | +-------+
  • 35. CODE EXAMPLES - ENUM JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 11 mysql> CREATE TABLE enum_test(e ENUM('fish', 'apple', 'dog') NOT NULL); mysql> INSERT INTO enum_test(e) VALUES('fish'), ('dog'), ('apple'); mysql> SELECT e + 0 FROM enum_test; mysql> SELECT e FROM enum_test ORDER BY e; +-------+ | e + 0 | +-------+ | 1 | | 3 | | 2 | +-------+ +-------+ | e | +-------+ | fish | | apple | | dog | +-------+
  • 36. CODE EXAMPLES – DATETIME NOT NULL JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 12 DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00‘
  • 37. AGENDA • Introduction (5min) • Strategic Overview (5min) • Design Considerations – Schema Optimization – Strategic (10min) • Design Considerations – Schema Optimization – Normalization (10min hopefully) • Indexing (5min) • Query Optimization (10min) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 13
  • 38. DESIGN CONSIDERATIONS SCHEMA OPTIMIZATION – NORMALIZATION JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 14
  • 39. DESIGN CONSIDERATIONS SCHEMA OPTIMIZATION – NORMALIZATION • Normalized data is non-redundant (Text book says this is the best option) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 14
  • 40. DESIGN CONSIDERATIONS SCHEMA OPTIMIZATION – NORMALIZATION • Normalized data is non-redundant (Text book says this is the best option) • Reality introduces de-normalization Welcome to Summary and Cache Tables JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 14
  • 41. CODE EXAMPLES – SUMMARY TABLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 15 mysql> CREATE TABLE msg_per_hr ( hr DATETIME NOT NULL, cnt INT UNSIGNED NOT NULL, PRIMARY KEY(hr) ); mysql> SELECT SUM(cnt) FROM msg_per_hr stored 23 hour WHERE hr BETWEEN CONCAT(LEFT(NOW(), 14), '00:00') - INTERVAL 23 HOUR concat rounds to nearest hr. AND CONCAT(LEFT(NOW(), 14), '00:00') - INTERVAL 1 HOUR; mysql> SELECT COUNT(*) FROM message first hour WHERE posted >= NOW() - INTERVAL 24 HOUR AND posted < CONCAT(LEFT(NOW(), 14), '00:00') - INTERVAL 23 HOUR; mysql> SELECT COUNT(*) FROM message last hour WHERE posted >= CONCAT(LEFT(NOW(), 14), '00:00');
  • 42. CODE EXAMPLES – CACHE TABLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 16 mysql> DROP TABLE IF EXISTS my_cache_new, my_cache_old; mysql> CREATE TABLE my_cache_new LIKE my_cache; -- populate my_cache_new as desired mysql> RENAME TABLE my_cache TO my_cache_old, my_cache_new TO my_cache;
  • 43. CODE EXAMPLES – COUNTER TABLE CONCURRENCY ISSUE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 17 mysql> CREATE TABLE hit_counter ( cnt INT UNSIGNED NOT NULL ) ENGINE=InnoDB; mysql> UPDATE hit_counter SET cnt = cnt + 1; mysql> SELECT cnt FROM hit_counter;
  • 44. CODE EXAMPLES – COUNTER TABLE CONCURRENCY SOLUTION JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 18 mysql> CREATE TABLE hit_counter ( slot TINYINT UNSIGNED NOT NULL PRIMARY KEY, cnt INT UNSIGNED NOT NULL ) ENGINE=InnoDB; mysql> INSERT INTO hit_counter VALUES (0,0), (1,0), (2,0), (3,0), … (99,0); mysql> UPDATE hit_counter SET cnt = cnt + 1 WHERE slot = RAND() * 100; mysql> SELECT SUM(cnt) FROM hit_counter;
  • 45. AGENDA • Introduction (5min) • Strategic Overview (5min) • Design Considerations – Schema Optimization – Strategic (10min) • Design Considerations – Schema Optimization – Normalization (10min hopefully) • Indexing (5min) • Query Optimization (10min) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 19
  • 46. INDEXING HASH INDEX JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 20
  • 47. INDEXING HASH INDEX • InnoDB creates adaptive hash indexes on frequent queries JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 20
  • 48. INDEXING HASH INDEX • InnoDB creates adaptive hash indexes on frequent queries • Main downside is that index doesn’t help sorting JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 20
  • 49. INDEXING HASH INDEX • InnoDB creates adaptive hash indexes on frequent queries • Main downside is that index doesn’t help sorting • Hash indexes can’t speed up range queries (WHERE age > 18) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 20
  • 50. INDEXING HASH INDEX – HOW TO – INCLUDING HASH COLLISION JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 21 mysql> SELECT id FROM url WHERE url="http://www.joomladagen.nl"; CREATE TABLE pseudohash ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, url VARCHAR(255) NOT NULL, url_crc INT UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY(id) ); CREATE TRIGGER pseudohash_crc_ins BEFORE INSERT ON pseudohash FOR EACH ROW BEGIN SET NEW.url_crc=crc32(NEW.url); CREATE TRIGGER pseudohash_crc_upd BEFORE UPDATE ON pseudohash FOR EACH ROW BEGIN SET NEW.url_crc=crc32(NEW.url); mysql> SELECT id FROM url WHERE url_crc=CRC32("http://www.joomladagen.nl") AND url="http://www.joomladagen.nl";
  • 51. INDEXING INDEX PROBLEMS JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 22 SELECT * FROM Orgchart SELECT a, c FROM Orgchart SELECT a, c FROM Orgchart WHERE lft - rgt = 1; WHERE lft - rgt = 1; WHERE lft =(rgt – 1); SELECT name FROM people mysql> ALTER TABLE people ADD KEY (idx_name(6)); WHERE name = ‘Hans’; CREATE TABLE t ( KEY(c1,c2,c3) ? KEY(c1,c3) Specificity! c1 INT, c2 INT, c3 INT, KEY(c1), KEY(c2), KEY(c3) );
  • 52. INDEXING INDEX PROBLEMS JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 22 SELECT * FROM Orgchart SELECT a, c FROM Orgchart SELECT a, c FROM Orgchart WHERE lft - rgt = 1; WHERE lft - rgt = 1; WHERE lft =(rgt – 1); SELECT name FROM people mysql> ALTER TABLE people ADD KEY (idx_name(6)); WHERE name = ‘Hans’; CREATE TABLE t ( KEY(c1,c2,c3) ? KEY(c1,c3) Specificity! c1 INT, c2 INT, c3 INT, KEY(c1), KEY(c2), KEY(c3) ); SELECT cc FROM payment WHERE staff_id = 2 AND customer_id = 584;
  • 53. INDEXING INDEX PROBLEMS JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 22 SELECT * FROM Orgchart SELECT a, c FROM Orgchart SELECT a, c FROM Orgchart WHERE lft - rgt = 1; WHERE lft - rgt = 1; WHERE lft =(rgt – 1); SELECT name FROM people mysql> ALTER TABLE people ADD KEY (idx_name(6)); WHERE name = ‘Hans’; CREATE TABLE t ( KEY(c1,c2,c3) ? KEY(c1,c3) Specificity! c1 INT, c2 INT, c3 INT, KEY(c1), KEY(c2), KEY(c3) ); SELECT cc FROM payment WHERE staff_id = 2 AND customer_id = 584; KEY(staff_id,customer_id) ?
  • 54. INDEXING INDEX PROBLEMS JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 22 SELECT * FROM Orgchart SELECT a, c FROM Orgchart SELECT a, c FROM Orgchart WHERE lft - rgt = 1; WHERE lft - rgt = 1; WHERE lft =(rgt – 1); SELECT name FROM people mysql> ALTER TABLE people ADD KEY (idx_name(6)); WHERE name = ‘Hans’; CREATE TABLE t ( KEY(c1,c2,c3) ? KEY(c1,c3) Specificity! c1 INT, c2 INT, c3 INT, KEY(c1), KEY(c2), KEY(c3) ); SELECT cc FROM payment WHERE staff_id = 2 AND customer_id = 584; KEY(staff_id,customer_id) ? SELECT SUM(staff_id = 2), SUM(customer_id = 584) FROM paymentG *************************** 1. row *************************** SUM(staff_id = 2): 7992 SUM(customer_id = 584): 30
  • 55. INDEXING INDEX PROBLEMS JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 22 SELECT * FROM Orgchart SELECT a, c FROM Orgchart SELECT a, c FROM Orgchart WHERE lft - rgt = 1; WHERE lft - rgt = 1; WHERE lft =(rgt – 1); SELECT name FROM people mysql> ALTER TABLE people ADD KEY (idx_name(6)); WHERE name = ‘Hans’; CREATE TABLE t ( KEY(c1,c2,c3) ? KEY(c1,c3) Specificity! c1 INT, c2 INT, c3 INT, KEY(c1), KEY(c2), KEY(c3) ); SELECT cc FROM payment WHERE staff_id = 2 AND customer_id = 584; KEY(staff_id,customer_id) ? SELECT SUM(staff_id = 2), SUM(customer_id = 584) FROM paymentG *************************** 1. row *************************** SUM(staff_id = 2): 7992 SUM(customer_id = 584): 30 ALTER TABLE payment ADD KEY(customer_id, staff_id);
  • 56. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) );
  • 57. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); WHERE age BETWEEN 18 AND 25 ORDER BY rating ASC
  • 58. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); WHERE age BETWEEN 18 AND 25 ORDER BY rating ASC MySQL can’t use added index if primary index uses range criterion
  • 59. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); WHERE age BETWEEN 18 AND 25 ORDER BY rating ASC MySQL can’t use added index if primary index uses range criterion KEY(sex, country)
  • 60. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); WHERE age BETWEEN 18 AND 25 ORDER BY rating ASC MySQL can’t use added index if primary index uses range criterion KEY(sex, country) NO Selectivity!!!
  • 61. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); WHERE age BETWEEN 18 AND 25 ORDER BY rating ASC MySQL can’t use added index if primary index uses range criterion KEY(sex, country) NO Selectivity!!! KEY(sex, country) Assumption: all searches will include sex and most will include country
  • 62. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 23 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); WHERE age BETWEEN 18 AND 25 ORDER BY rating ASC MySQL can’t use added index if primary index uses range criterion KEY(sex, country) NO Selectivity!!! KEY(sex, country) Assumption: all searches will include sex and most will include country Trick: AND sex IN('m', 'f')
  • 63. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 24 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) );
  • 64. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 24 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); (sex, country, age) (sex, country, region, age) (sex, country, region, city, age)
  • 65. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 24 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); (sex, country, age) (sex, country, region, age) (sex, country, region, city, age) Using the IN() trick, we can implement just the (sex, country, region, city, age) index.
  • 66. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 24 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); (sex, country, age) (sex, country, region, age) (sex, country, region, city, age) Using the IN() trick, we can implement just the (sex, country, region, city, age) index. Why is age at end?
  • 67. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 24 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); (sex, country, age) (sex, country, region, age) (sex, country, region, city, age) Using the IN() trick, we can implement just the (sex, country, region, city, age) index. Why is age at end? Remember our range problem? MySQL uses indexes from left to right unit the first range query Trick: Convert WHERE age BETWEEN 18 and 25 to WHERE age IN(18,19,20,21,22,23,24,25)
  • 68. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 25 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); SELECT age, country, …. , name FROM profiles WHERE sex=‘F‘ ORDER BY rating LIMIT 100000, 10; Retrieving 100’010 rows, discarding 100’000 If data load per row is 15kb calculated data is 18.32Mb and we’re discarding 18.31Mb! SELECT age, country, …. , name FROM profiles INNER JOIN ( SELECT id FROM profiles WHERE x.sex='M‘ ORDER BY rating LIMIT 100000, 10 ) AS x USING(id);
  • 69. INDEXING EXAMPLE JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 25 CREATE TABLE profile( id INT UNSIGNED NOT NULL AUTO_INCREMENT, sex CHAR(1) NOT NULL, age TINYINT NOT NULL, country VARCHAR(255) NOT NULL, region VARCHAR(255) NOT NULL DEFAULT ‘’, city VARCHAR(255) NOT NULL DEFAULT ‘’, color_hair VARCHAR(255) NOT NULL DEFAULT ‘’, color_eyes VARCHAR(255) NOT NULL DEFAULT ‘’, name … … rating TINYINT NOT NULL DEFAULT 1, PRIMARY KEY(id) ); KEY(sex, rating) SELECT age, country, …. , name FROM profiles WHERE sex=‘F‘ ORDER BY rating LIMIT 100000, 10; Retrieving 100’010 rows, discarding 100’000 If data load per row is 15kb calculated data is 18.32Mb and we’re discarding 18.31Mb! SELECT age, country, …. , name FROM profiles INNER JOIN ( SELECT id FROM profiles WHERE x.sex='M‘ ORDER BY rating LIMIT 100000, 10 ) AS x USING(id);
  • 70. AGENDA • Introduction (5min) • Strategic Overview (5min) • Design Considerations – Schema Optimization – Strategic (10min) • Design Considerations – Schema Optimization – Normalization (10min hopefully) • Indexing (5min) • Query Optimization (10min) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 26
  • 71. QUERY OPTIMIZATION TOO MUCH DATA JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27 SELECT * FROM Orgchart WHERE lft - rgt = 1;
  • 72. QUERY OPTIMIZATION TOO MUCH DATA JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27 SELECT * FROM Orgchart WHERE lft - rgt = 1;
  • 73. QUERY OPTIMIZATION TOO MUCH DATA JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27 SELECT * FROM Orgchart WHERE lft - rgt = 1; SELECT * FROM recipes.ingredient INNER JOIN recipes.recipe_ingredient USING(ingredient_id) INNER JOIN recipes.recipe USING(recipe_id) WHERE recipes.recipe.name = ‘Stroopwafel';
  • 74. QUERY OPTIMIZATION TOO MUCH DATA JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27 SELECT * FROM Orgchart WHERE lft - rgt = 1; SELECT * FROM recipes.ingredient INNER JOIN recipes.recipe_ingredient USING(ingredient_id) INNER JOIN recipes.recipe USING(recipe_id) WHERE recipes.recipe.name = ‘Stroopwafel'; All I want is the ingredients for a Stroopwafel This Query returns all columns for all three tables!
  • 75. QUERY OPTIMIZATION TOO MUCH DATA JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27 SELECT * FROM Orgchart WHERE lft - rgt = 1; SELECT * FROM recipes.ingredient INNER JOIN recipes.recipe_ingredient USING(ingredient_id) INNER JOIN recipes.recipe USING(recipe_id) WHERE recipes.recipe.name = ‘Stroopwafel'; All I want is the ingredients for a Stroopwafel This Query returns all columns for all three tables! SELECT recipes.ingredient.* FROM recipes.ingredient ... ;
  • 76. QUERY OPTIMIZATION TOO MUCH DATA JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27 SELECT * FROM Orgchart WHERE lft - rgt = 1; SELECT * FROM recipes.ingredient INNER JOIN recipes.recipe_ingredient USING(ingredient_id) INNER JOIN recipes.recipe USING(recipe_id) WHERE recipes.recipe.name = ‘Stroopwafel'; All I want is the ingredients for a Stroopwafel This Query returns all columns for all three tables! SELECT recipes.ingredient.* FROM recipes.ingredient ... ;
  • 77. QUERY OPTIMIZATION TOO MUCH DATA JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27 SELECT * FROM Orgchart WHERE lft - rgt = 1; SELECT * FROM recipes.ingredient INNER JOIN recipes.recipe_ingredient USING(ingredient_id) INNER JOIN recipes.recipe USING(recipe_id) WHERE recipes.recipe.name = ‘Stroopwafel'; All I want is the ingredients for a Stroopwafel This Query returns all columns for all three tables! SELECT recipes.ingredient.* FROM recipes.ingredient ... ; SELECT img, name, …, comment FROM comments WHERE user_id = 123983;
  • 78. QUERY OPTIMIZATION TOO MUCH DATA JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27 SELECT * FROM Orgchart WHERE lft - rgt = 1; SELECT * FROM recipes.ingredient INNER JOIN recipes.recipe_ingredient USING(ingredient_id) INNER JOIN recipes.recipe USING(recipe_id) WHERE recipes.recipe.name = ‘Stroopwafel'; All I want is the ingredients for a Stroopwafel This Query returns all columns for all three tables! SELECT recipes.ingredient.* FROM recipes.ingredient ... ; SELECT img, name, …, comment FROM comments WHERE user_id = 123983; What, did the image and name change in the last 2microseconds?!?
  • 79. QUERY OPTIMIZATION TOO MUCH DATA JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 27 SELECT * FROM Orgchart WHERE lft - rgt = 1; SELECT * FROM recipes.ingredient INNER JOIN recipes.recipe_ingredient USING(ingredient_id) INNER JOIN recipes.recipe USING(recipe_id) WHERE recipes.recipe.name = ‘Stroopwafel'; All I want is the ingredients for a Stroopwafel This Query returns all columns for all three tables! SELECT recipes.ingredient.* FROM recipes.ingredient ... ; SELECT img, name, …, comment FROM comments WHERE user_id = 123983; What, did the image and name change in the last 2microseconds?!? SELECT img, name, …, FROM comments WHERE user_id = 123983; SELECT comment FROM comments WHERE user_id = 123983;
  • 80. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 28
  • 81. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 28 DELETE FROM messages WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH);
  • 82. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 28 DELETE FROM messages WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH); <?php … $rows_affected = 0; do { $rows_affected = do_query(" DELETE FROM messages WHERE created < DATE_SUB(NOW(),INTERVAL 3 MONTH) LIMIT 10000 "); } while $rows_affected > 0;
  • 83. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29
  • 84. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29 SELECT * FROM tag JOIN tag_post ON tag_post.tag_id=tag.id JOIN post ON tag_post.post_id=post.id WHERE tag.tag=‘joomladagen';
  • 85. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29 SELECT * FROM tag JOIN tag_post ON tag_post.tag_id=tag.id JOIN post ON tag_post.post_id=post.id WHERE tag.tag=‘joomladagen'; SELECT * FROM tag WHERE tag='joomladagen'; SELECT * FROM tag_post WHERE tag_id=1234; SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904);
  • 86. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29 SELECT * FROM tag JOIN tag_post ON tag_post.tag_id=tag.id JOIN post ON tag_post.post_id=post.id WHERE tag.tag=‘joomladagen'; SELECT * FROM tag WHERE tag='joomladagen'; SELECT * FROM tag_post WHERE tag_id=1234; SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904); WHY? DENORMALIZED ?!?
  • 87. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29 SELECT * FROM tag JOIN tag_post ON tag_post.tag_id=tag.id JOIN post ON tag_post.post_id=post.id WHERE tag.tag=‘joomladagen'; SELECT * FROM tag WHERE tag='joomladagen'; SELECT * FROM tag_post WHERE tag_id=1234; SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904); WHY? DENORMALIZED ?!? • Query cache validation of 3 tables instead of one
  • 88. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29 SELECT * FROM tag JOIN tag_post ON tag_post.tag_id=tag.id JOIN post ON tag_post.post_id=post.id WHERE tag.tag=‘joomladagen'; SELECT * FROM tag WHERE tag='joomladagen'; SELECT * FROM tag_post WHERE tag_id=1234; SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904); WHY? DENORMALIZED ?!? • Query cache validation of 3 tables instead of one • Lock contention (?)
  • 89. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29 SELECT * FROM tag JOIN tag_post ON tag_post.tag_id=tag.id JOIN post ON tag_post.post_id=post.id WHERE tag.tag=‘joomladagen'; SELECT * FROM tag WHERE tag='joomladagen'; SELECT * FROM tag_post WHERE tag_id=1234; SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904); WHY? DENORMALIZED ?!? • Query cache validation of 3 tables instead of one • Lock contention (?) • Query index lookup of IN() is better than with JOINS
  • 90. QUERY OPTIMIZATION DIVIDE AND CONQUER JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 29 SELECT * FROM tag JOIN tag_post ON tag_post.tag_id=tag.id JOIN post ON tag_post.post_id=post.id WHERE tag.tag=‘joomladagen'; SELECT * FROM tag WHERE tag='joomladagen'; SELECT * FROM tag_post WHERE tag_id=1234; SELECT * FROM post WHERE post.id IN(123,456,567,9098,8904); WHY? DENORMALIZED ?!? • Query cache validation of 3 tables instead of one • Lock contention (?) • Query index lookup of IN() is better than with JOINS • Potential for application caching
  • 91. AGENDA • Introduction (5min) • Strategic Overview (5min) • Design Considerations – Schema Optimization – Strategic (10min) • Design Considerations – Schema Optimization – Normalization (10min hopefully) • Indexing (5min) • Query Optimization (10min) JOOMLADAY NETHERLANDS 2013 - ELI ASCHKENASY - @ELIASCHKENASY 30