Posts Tagged ‘optimisation’

9
mar

Sortie du livre: Audit et optimisation – MySQL 5

   Posted by: freshdaz    in Divers, MySQL

Pascal Borghino, Olivier Dasini, Arnaud Gadal et Eyrolles ont l’honneur de vous annoncer la sortie du livre Audit et optimisation MySQL 5.

Bonnes pratiques pour l'administrateur

Pour la première fois, les meilleurs experts de chez Yahoo!, Orange Business Services et Virgin mobile livrent leur expérience de terrain... en français

Editeur : EYROLLES | Langue : Français | ISBN-10: 2212126344 | ISBN-13: 978-2212126341

A l’occasion du salon Solutions Linux/Open Source qui se tiendra du 16 au 18 mars à Paris Expo-Porte de Versailles, cet ouvrage sera disponible en exclusivité et en avant-première sur le stand Eyrolles (n°C35).

L’ouvrage sera disponible en librairie le 25 mars 2010. Vous pouvez cependant déjà le commander sur les sites spécialisés (fnac, amazon.fr, eyrollesLavoisier, decitre. cine-memento.fr,… )

Au sommaire:

CHAPITRE 1
Gérer une situation d’urgence avec MySQL ………………………….. 1
CHAPITRE 2
Choisir son serveur MySQL ………………………………………………… 19
CHAPITRE 3
Les moteurs de stockage …………………………………………………… 49
CHAPITRE 4
Surveiller son serveur MySQL…………………………………………….. 81
CHAPITRE 5
Exploiter les journaux de MySQL ……………………………………… 141
CHAPITRE 6
Optimiser sa base de données : du schéma aux requêtes ………. 163
CHAPITRE 7
Optimiser son serveur mySQL ………………………………………….. 193
CHAPITRE 8
La réplication MySQL ………………………………………………………. 217
CHAPITRE 9
Où trouver de l’aide ? ……………………………………………………… 253

Tags: , , ,


Le but de cet article est d’optimiser une simple requête  (SELECT avg(Population) FROM city GROUP BY CountryCode) et surtout de comprendre comment l’optimiseur procède, en étudiant les résultats donnés par les variables qui permettent de surveiller le serveur MySQL.

Le schéma utilisé est le schéma world téléchargeable ici

Voici la structure de la table city:

SHOW CREATE TABLE city\G
*************************** 1. row ***************************
Table: city
Create Table: CREATE TABLE city (
ID int(11) NOT NULL AUTO_INCREMENT,
Name char(35) NOT NULL DEFAULT  »,
CountryCode char(3) NOT NULL DEFAULT  »,
District char(20) NOT NULL DEFAULT  »,
Population int(11) NOT NULL DEFAULT ’0′,
PRIMARY KEY (ID)
) ENGINE=MyISAM AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1


La commande EXPLAIN, permet d’avoir le plan d’exécution:

EXPLAIN SELECT avg(Population) FROM city GROUP BY CountryCode\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: c
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4079
Extra: Using temporary; Using filesort

L’optimiseur fait un full table scan (type: ALL) ce qui n’est pas forcement une bonne nouvelle. De plus aucun index n’est utilisé (key: NULL), ce qui est logique car la table n’en contient pas (sic !)
Using temporary; Using filesort indiquent la création d’un table temporaire et le tri des données (pas très bon pour les performances surtout si la table temporaire est créée sur le disque)

La variable Last_query_cost permet de récupérer le coût de la requête:

SHOW STATUS LIKE ‘Last_query_cost’\G

*************************** 1. row ***************************
Variable_name: Last_query_cost
Value: 4963.520924

Ajoutons un index sur la colonne countrycode:

ALTER TABLE city ADD INDEX Idx_cc(CountryCode);

SHOW CREATE TABLE city\G
*************************** 1. row ***************************
Table: city
Create Table: CREATE TABLE city (
ID int(11) NOT NULL AUTO_INCREMENT,
Name char(35) NOT NULL DEFAULT  »,
CountryCode char(3) NOT NULL DEFAULT  »,
District char(20) NOT NULL DEFAULT  »,
Population int(11) NOT NULL DEFAULT ’0′,
PRIMARY KEY (ID),
KEY Idx_cc (CountryCode)
) ENGINE=MyISAM AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1

EXPLAIN SELECT avg(Population) FROM city GROUP BY CountryCode\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: city
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4079
Extra: Using temporary; Using filesort



L’index Idx_cc ne sert à rien

Ajoutons alors un index sur la colonne population

ALTER TABLE city ADD INDEX Idx_population(Population);

SHOW CREATE TABLE city\G
*************************** 1. row ***************************
Table: city
Create Table: CREATE TABLE city (
ID int(11) NOT NULL AUTO_INCREMENT,
Name char(35) NOT NULL DEFAULT  »,
CountryCode char(3) NOT NULL DEFAULT  »,
District char(20) NOT NULL DEFAULT  »,
Population int(11) NOT NULL DEFAULT ’0′,
PRIMARY KEY (ID),
KEY Idx_cc (CountryCode),
KEY Idx_population (Population)
) ENGINE=MyISAM AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

EXPLAIN SELECT avg(Population) FROM city GROUP BY CountryCode\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: c
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 4079
Extra: Using temporary; Using filesort


Pas mieux ! L’index Idx_population ne sert à rien.

Effacement des 2 index:

ALTER TABLE city DROP INDEX Idx_cc, DROP INDEX Idx_population;


Ajoutons un index composite sur les colonnes population, countrycode:

ALTER TABLE city ADD INDEX Idx_population_cc(Population, CountryCode);

SHOW CREATE TABLE city\G
*************************** 1. row ***************************
Table: city
Create Table: CREATE TABLE `city` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` char(35) NOT NULL DEFAULT  »,
`CountryCode` char(3) NOT NULL DEFAULT  »,
`District` char(20) NOT NULL DEFAULT  »,
`Population` int(11) NOT NULL DEFAULT ’0′,
PRIMARY KEY (`ID`),
KEY `Idx_population_cc` (`Population`,`CountryCode`)
) ENGINE=MyISAM AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1

EXPLAIN SELECT avg(Population) FROM city GROUP BY CountryCode\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: c
type: index
possible_keys: NULL
key: Idx_population_cc
key_len: 7
ref: NULL
rows: 4079
Extra: Using index; Using temporary; Using filesort



Çaparait un peu meilleur, l’index Idx_population_cc est utilisé.
Extra: using index nous indique que MySQL utilise un index couvrant (covering index), c’est à dire que l’information est entièrement accessible en parcourant l’index (pas d’accès aux données).
De  plus l’optimiseur fait un full index scan:  type: index

Voyons le coût de la requête:

SHOW STATUS LIKE ‘Last_query_cost’\G
*************************** 1. row ***************************
Variable_name: Last_query_cost
Value: 4963.520924


La valeur de (l’obscure) Last_query_cost est cependant le même que pour les requêtes précédentes…

Ajoutons un index composite sur les colonnes countrycode,population

ALTER TABLE test2.city ADD INDEX Idx_cc_population(CountryCode,Population);

SHOW CREATE TABLE city\G
*************************** 1. row ***************************
Table: city
Create Table: CREATE TABLE `city` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Name` char(35) NOT NULL DEFAULT  »,
`CountryCode` char(3) NOT NULL DEFAULT  »,
`District` char(20) NOT NULL DEFAULT  »,
`Population` int(11) NOT NULL DEFAULT ’0′,
PRIMARY KEY (`ID`),
KEY `Idx_population_cc` (`Population`,`CountryCode`),
KEY `Idx_cc_population` (`CountryCode`,`Population`)
) ENGINE=MyISAM AUTO_INCREMENT=4080 DEFAULT CHARSET=latin1

EXPLAIN SELECT AVG(Population) FROM city GROUP BY CountryCode\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: c
type: index
possible_keys: NULL
key: Idx_cc_population
key_len: 7
ref: NULL
rows: 4079
Extra: Using index
1 row in set (0.00 sec)

SHOW STATUS LIKE ‘Last_query_cost’\G
*************************** 1. row ***************************
Variable_name: Last_query_cost
Value: 4963.520924


L’optimiseur estime que le coût de la requête est toujours le même, cependant l’index Idx_cc_population(CountryCode,Population) optimise les performance de notre requête car il n’y a plus de Using temporary ni de Using filesort.
Il suffit de pousser encore un peu plus loin notre analyse pour en être définitivement (?) convaincu…

Initialisation des variables de sessions

FLUSH STATUS;


En utilisant l’index idx_population_cc (le mauvais index)

SELECT AVG(Population) FROM city use index(idx_population_cc) GROUP BY CountryCode;
232 rows in set (0.00 sec)

SHOW STATUS LIKE ‘handler%’;
 +----------------------------+-------+
 | Variable_name              | Value |
 +----------------------------+-------+
 | Handler_commit             | 0     |
 | Handler_delete             | 0     |
 | Handler_discover           | 0     |
 | Handler_prepare            | 0     |
 | Handler_read_first         | 1     |
 | Handler_read_key           | 4079  |
 | Handler_read_next          | 4079  |
 | Handler_read_prev          | 0     |
 | Handler_read_rnd           | 232   |
 | Handler_read_rnd_next      | 233   |
 | Handler_rollback           | 0     |
 | Handler_savepoint          | 0     |
 | Handler_savepoint_rollback | 0     |
 | Handler_update             | 3847  |
 | Handler_write              | 232   |
 +----------------------------+-------+


Les handler sont des indicateurs liés au moteur de stockage.
Handler_read_first comptabilise le nombre de fois que la première valeur de l’index est lue.
Handler_read_key indique le nombre d’enregistrement récupéré graçe à l’index.
Handler_read_next indique une lecture ordonnée de l’index (une valeur, puis la suivante, puis la suivante…).
Handler_read_first, Handler_read_key &  Handler_read_next, indiquent là, un full index scan

Handler_read_rnd & Handler_read_rnd_next indiquent un full table scan sur la table temporaire

Handler_update nous donne une indication sur le nombre de mise à jours dans la table temporaire (à cause du tri)
Handler_write indique le nombre de lignes insérées dans la table temporaire

Ces 2 derniers paramètres confirme donc la création de la table temporaire et l’opération de tri

Pour avoir plus d’informations sur le tri:

SHOW SESSION STATUS LIKE ‘sort%’;
 +-------------------+-------+
 | Variable_name     | Value |
 +-------------------+-------+
 | Sort_merge_passes | 0     |
 | Sort_range        | 0     |
 | Sort_rows         | 232   |
 | Sort_scan         | 1     |
 +-------------------+-------+


Sort_rows: nombre de lignes triées (nombre d’enregistrements de la table temporaire).
Sort_scan: nombre de tri.

SHOW SESSION STATUS LIKE ‘created%’;
 +-------------------------+-------+
 | Variable_name           | Value |
 +-------------------------+-------+
 | Created_tmp_disk_tables | 0     |
 | Created_tmp_files       | 0     |
 | Created_tmp_tables      | 1     |
 +-------------------------+-------+


Created_tmp_tables: nombre de table temporaire crée. La bonne nouvelle est que la table temporaire est créee en mémoire (Created_tmp_disk_tables=0)


réinitialise les variables de sessions

FLUSH STATUS;

En utilisant l’index idx_cc_population (le bon index)

SELECT AVG(Population) FROM city use index(idx_population_cc) GROUP BY CountryCode;
232 rows in set (0.00 sec)

SHOW STATUS LIKE ‘handler%’;

 +----------------------------+-------+
 | Variable_name              | Value |
 +----------------------------+-------+
 | Handler_commit             | 0     |
 | Handler_delete             | 0     |
 | Handler_discover           | 0     |
 | Handler_prepare            | 0     |
 | Handler_read_first         | 1     |
 | Handler_read_key           | 0     |
 | Handler_read_next          | 4079  |
 | Handler_read_prev          | 0     |
 | Handler_read_rnd           | 0     |
 | Handler_read_rnd_next      | 0     |
 | Handler_rollback           | 0     |
 | Handler_savepoint          | 0     |
 | Handler_savepoint_rollback | 0     |
 | Handler_update             | 0     |
 | Handler_write              | 0     |
 +----------------------------+-------+


Handler_read_first &  Handler_read_next valident le full index scan et puis c’est tout :)

SHOW SESSION STATUS LIKE ‘sort%’;
 +-------------------+-------+
 | Variable_name     | Value |
 +-------------------+-------+
 | Sort_merge_passes | 0     |
 | Sort_range        | 0     |
 | Sort_rows         | 0     |
 | Sort_scan         | 0     |
 +-------------------+-------+


pas de tri

SHOW SESSION STATUS LIKE ‘created%’;
 +-------------------------+-------+
 | Variable_name           | Value |
 +-------------------------+-------+
 | Created_tmp_disk_tables | 0     |
 | Created_tmp_files       | 0     |
 | Created_tmp_tables      | 0     |
 +-------------------------+-------+

pas de table(s) temporaire(s)

cqfd

Tags: ,

17
nov

Présentation : Optimiser MySQL

   Posted by: freshdaz    in Conférence, MySQL, Présentation

Optimiser sa base de donnée est l’obsession principale du DBA. Savoir identifier, anticiper et régler les problèmes de performances constituent une vrai valeur ajoutée et cela n’est pas donné à tout le monde.  Satisfaction personnelle, satisfaction des décideurs mais surtout satisfaction du client

http://dasini.net/blog/presentations/?#optimiser_mysql

Tags: ,

Mercredi 19 novembre 2008, MySQL/SUN organise sa deuxième conférence française.

Pourquoi y aller ?

  • Découvrir les meilleures pratiques pour déployer et gérer les applications MySQL à travers votre entreprise
  • Comprendre comment bénéficier des nouvelles technologies telles que memcached et MySQL Proxy
  • Obtenir des informations détaillées sur les nouvelles fonctions, produits et services MySQL
  • Bénéficier de conseils de spécialistes sur l’optimisation des performances de MySQL
  • Développer vos compétences pour bâtir des applications MySQL fortement évolutives, fiables, sécurisées et à haute disponibilité
  • Écouter des témoignages clients sur la mise en place d’applications MySQL
  • Apprendre comment mettre en place un entrepôt de données de plusieurs téra-octets avec MySQL et Infobright
  • Établir des relations et échanger avec d’autres utilisateurs MySQL et avec les membres de l’équipe MySQL de SUN

Au programme
Les conférences

  • Le Futur de MySQL: Ce que vous devez savoir sur les fonctionnalités et services à venir
  • Délivrer des applications Web 2.0 avec MySQL et memcached
  • Meilleures pratiques pour déployer MySQL sur Solaris
  • Haute disponibilité avec load balancing & MySQL Proxy
  • Choisir la bonne solution HA pour MySQL
  • Le datawarehouse multi-téraoctets avec MySQL et Infobright
  • Les performances MySQL sous microscope
  • Stratégies de Backup pour MySQL
  • Scale Up, Scale Out, Virtualisation—Que devez-vous faire avec MySQL ?

Présentations clients

  • Kewego
  • Virgin Mobile

Intervenants

  • Bertrand Matthelié, Directeur Marketing EMEA MySQL
  • Bruno Hourdel, Directeur Marketing Sun France
  • Robin Schumacher, Directeur Product Management MySQL
  • Serge Frezefond, Ingénieur avant-vente
  • Eric Bezille, Chief Technologist
  • Philippe Campos, consultant sénior
  • Max Mether, instructeur
  • Miriam Tuerk, CEO Infobright
  • Stéphane Varoqui, consultant sénior

Date
mercredi 19 novembre 2008

Lieu
Hotel Le Méridien Etoile
81 Boulevard Gouvion Saint-Cyr
75017 Paris
Tel : 01 40 68 34 34
Prix
Le prix de la conférence est de 199 EUR incluant le déjeuner.

Alléchant tout ça, moi j’y serai :)

Tags: , , , , , , , , ,