web-dev-qa-db-fra.com

MySQL crée des tables temporaires sur le disque. Comment puis-je l'arrêter?

Nous gérons un site (Moodle) que les utilisateurs trouvent actuellement lent. Je pense avoir trouvé le problème de la création de tables temporaires sur disque par MySQL. Je regarde la variable created_tmp_disk_tables Dans l'administration du serveur Mysql Workbench et le nombre augmente avec environ 50 tables/s. Après une journée d'utilisation, created_tmp_disk_tables Est> 100k. De plus, la mémoire ne semble pas être libérée. L'utilisation continue d'augmenter jusqu'à ce que le système devienne à peu près inutilisable et que nous devions redémarrer MySQL. Je dois le redémarrer presque tous les jours et cela commence par utiliser environ 30 à 35% de la mémoire disponible et terminer la journée à 80%.

Je n'ai aucun blob dans la base de données et aucun contrôle sur les requêtes non plus, je ne peux donc pas essayer de les optimiser. J'ai également utilisé le Percona Confirguration Wizard pour générer un fichier de configuration mais que my.ini n'a pas résolu mon problème non plus.

Des questions

  1. Que dois-je changer pour empêcher MySQL de créer des tables temporaires sur le disque? Y a-t-il des paramètres que je dois modifier? Dois-je y jeter plus de mémoire?

  2. Comment puis-je empêcher MySQL de manger ma mémoire?

Éditer

J'ai activé le journal slow_queries Et découvert que la requête SELECT GET_LOCK() était enregistrée comme lente. Une recherche rapide a révélé que j'avais autorisé des connexions persistantes dans la configuration PHP (mysqli.allow_persistent = ON). J'ai désactivé cette option. Cela a réduit la vitesse à laquelle MySQL consomme de la mémoire. la création de tables temporaires cependant.

J'ai également vérifié que le key_buffer size Est suffisamment grand. J'ai regardé la variable key_writes. Cela devrait être nul. Sinon, augmentez le key_buffer_size. J'ai zéro key_reads Et zéro key_writes Donc je suppose que le key_buffer_size Est assez grand.

J'ai augmenté les tmp_table_size Et max-heap-table-size À 1024M car une augmentation de created_tmp_disk_tables peut indiquer que les tables ne peuvent pas tenir en mémoire. Cela ne l'a pas résolu.

Réf: http://www.mysqlperformanceblog.com/2007/08/16/how-much-overhead-is-caused-by-on-disk-temporary-tables/

Modifier 2

Si vous voyez plusieurs sort_merge_passes Par seconde dans la sortie SHOW GLOBAL STATUS, vous pouvez envisager d'augmenter la valeur de sort_buffer_size. J'ai eu 2 sort_merge_passes En une heure donc je considère que le sort_buffer_size Est assez grand.

Ref: Manuel Mysql sur sort_buffer_size

Modifier 3

J'ai modifié les tampons de tri et de jointure comme suggéré par @RolandoMySQLDBA. Le résultat est affiché dans le tableau ci-dessous mais je pense que le created_tmp_tables_on_disk Est toujours élevé. J'ai redémarré le serveur mysql après avoir changé la valeur et vérifié le created_tmp_tables_on_disk Après une journée (8h) et calculé la moyenne. D'autres suggestions? Il me semble qu'il y a quelque chose qui ne rentre pas dans une sorte de récipient mais je ne peux pas comprendre ce que c'est.

+---------------------+-------------+-------------+--------------------+
| Tmp_table_size,     | Sort_buffer | Join_buffer | No of created      |
| max_heap_table_size |             |             | tmp_tables on disk |
+---------------------+-------------+-------------+--------------------+
| 125M                | 256K        | 256K        |  100k/h            |
+---------------------+-------------+-------------+--------------------+
| 125M                | 512K        | 512K        |  100k/h            |
+---------------------+-------------+-------------+--------------------+
| 125M                | 1M          | 1M          |  100k/h            |
+---------------------+-------------+-------------+--------------------+
| 125M                | 4M          | 4M          |  100k/h            |
+---------------------+-------------+-------------+--------------------+   



Voici ma configuration:

+-----------------------+-----------------------+
|DATABASE SERVER        |WEB SERVER             |
+-----------------------+-----------------------+
|Windows Server 2008 R2 |Windows Server 2008 R2 |
+-----------------------+-----------------------+
|MySQL 5.1.48           |IIS 7.5                |
+-----------------------+-----------------------+
|4 Core CPU             |4 Core CPU             |
+-----------------------+-----------------------+
|4GB RAM                |8GB RAM                |
+-----------------------+-----------------------+

Informations supplémentaires

+--------------------+---------+
|PARAM               |VALUE    |
+--------------------+---------+
|Num of tables in Db |361      |
+--------------------+---------+
|Size of database    |2.5G     |
+--------------------+---------+
|Database engine     |InnoDB   |
+--------------------+---------+
|Read/write ratio    |3.5      |
|(Innodb_data_read/  |         |
|innodb_data_written)|         |
+--------------------+---------+
|Avg table size      |15k rows |
+--------------------+---------+
|Max table size      |744k rows|
+--------------------+---------+

Cette configuration m'a été donnée, j'ai donc un contrôle limité sur elle. Le serveur Web utilise très peu de CPU et RAM donc j'ai exclu cette machine comme goulot d'étranglement. La majorité des paramètres MySQL provient d'un outil de génération automatique de configuration.

J'ai surveillé le système à l'aide de PerfMon pendant quelques jours représentatifs. De là, je conclus que ce n'est pas le système d'exploitation qui échange sur le disque.

My.ini

[client]
port=3306
[mysql]
default-character-set=utf8

[mysqld]
port=3306
basedir="C:/Program Files/MySQL/MySQL Server 5.1/"
datadir="D:/DBs/Data/"
default-character-set=utf8
default-storage-engine=INNODB
sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
max_connections=125
query_cache_size=350M
table_cache=1520
tmp_table_size=125M
table-definition-cache= 1024
max-heap-table-size= 32M
thread_cache_size=38

MyISAM Specific options
myisam_max_sort_file_size=100G
myisam_sort_buffer_size=125M
key_buffer_size=55M
read_buffer_size=1024K
read_rnd_buffer_size=256K
sort_buffer_size=1024K
join_buffer_size=1024K


INNODB Specific options
innodb_data_home_dir="D:/DBs/"
innodb_additional_mem_pool_size=32M
innodb_flush_log_at_trx_commit=1
innodb_log_buffer_size=16M
innodb_buffer_pool_size=2G
innodb_log_file_size=407M
innodb_thread_concurrency=8
29
user30431

En regardant le my.ini, J'ai deux suggestions

SUGGESTION # 1

Je voudrais augmenter les paramètres suivants dans votre my.ini

sort_buffer_size=4M
join_buffer_size=4M

Cela fera que certaines jointures et tri resteront en mémoire. Bien sûr, une fois un JOIN ou un ORDER BY a besoin de plus de 4M, il sera paginé sur le disque en tant que table MyISAM.

Si vous ne pouvez pas vous connecter en tant que root@localhost, puis redémarrez mysql avec

C:\> net stop mysql
C:\> net start mysql

Si vous pouvez vous connecter en tant que root @ localhost, vous n'avez pas besoin de redémarrer mysql pour utiliser ces paramètres.

Exécutez simplement ceci dans le client MySQL:

SET @FourMegs = 1024 * 1024 * 4;
SET GLOBAL sort_buffer_size = @FourMegs;
SET GLOBAL join_buffer_size = @FourMegs;

SUGGESTION # 2

Étant donné que vos données se trouvent sur Drive D:, vous pouvez avoir des E/S disque sur le lecteur C:.

Veuillez exécuter cette requête:

mysql> show variables like 'tmpdir';
+---------------+-----------------+
| Variable_name | Value           |
+---------------+-----------------+
| tmpdir        | C:\Windows\TEMP |
+---------------+-----------------+
1 row in set (0.00 sec)

Puisque j'exécute mysql sur mon bureau avec des valeurs par défaut, mes tables temporaires sont écrites sur Drive C:. Si le lecteur D est un meilleur disque que le lecteur C:, vous pouvez peut-être mapper les tables temporaires sur Drive D: en définissant tmpdir dans my.ini comme suit:

tmpdir="D:/DBs/"

Vous devrez redémarrer mysql car tmpdir n'est pas une variable dynamique.

Essaie !!!

MISE À JOUR 2013-11-29 10:09 EST

SUGGESTION # 3

Étant donné que MySQL fonctionne sous Windows et que vous ne pouvez pas toucher aux requêtes dans le package de base, j'ai deux idées à faire ensemble.

IDÉE # 1: déplacer la base de données vers une machine Linux

Tu devrais être capable de

  • Configurer une machine Linux
  • Installer MySQL sur la machine Linux
  • Activer la journalisation binaire pour MySQL sous Windows
  • mysqldump la base de données dans un fichier texte SQL
  • Charger un fichier SQL sur MySQL fonctionnant sous Linux
  • Configuration de la réplication de MySQL/Windows vers MySQL/Linux

IDÉE # 2: Reconfigurez Moodle pour pointer vers la machine Linux

Moodle a été conçu pour LAMP en premier lieu. Modifiez simplement les fichiers de configuration pour pointer vers la machine Linux au lieu de localhost.

Voici un lien vers un ancien document Moodle 2.3 sur la configuration de MySQL: http://docs.moodle.org/23/en/Installing_Moodle#Create_an_empty_database

Je suis sûr que les derniers documents sont également disponibles.

Quel est l'intérêt de déplacer la base de données vers Linux ???

Comment cela aide-t-il la situation de la table temporaire ???

Je suggérerais alors de configurer un RAM comme dossier cible pour vos tables temporaires

La création de la table temporaire se fera toujours, mais elle sera écrite dans RAM plutôt que sur disque. Réduisant les E/S disque.

MISE À JOUR 2013-11-29 11:24 EST

SUGGESTION # 4

Je suggère de revisiter SUGGESTION # 2 avec un disque RAID-0 rapide (32+ Go), en le configurant comme lecteur T: (T pour Temp). Après avoir installé un tel disque, ajoutez-le à my.ini:

[mysqld]
tmpdir="T:\"

Un redémarrage de MySQL serait requis, en utilisant

net stop mysql
net start mysql

BTW J'ai dit RAID-0 exprès afin que vous puissiez obtenir de bonnes performances d'écriture sur un RAID-1, RAID-10. Un disque de table tmp n'est pas quelque chose que je rendrais redondant.

Sans optimiser les requêtes sur lesquelles @RaymondNijland a commenté, vous ne pouvez en aucun cas réduire le nombre de création de table temporaire. SUGGESTION #3 et SUGGESTION #4 offre d'accélérer la création de table temporaire et les E/S de table temporaire comme seule alternative.

16
RolandoMySQLDBA

Je réponds à ma propre question ici pour être complet

Je vais sélectionner @RolandoMySQLDBA comme réponse préférée car cela m'a donné le plus d'indices même si cela n'a pas vraiment résolu mon problème.

Voici les résultats de mon enquête

Conclusion

MySQL sur Windows crée juste beaucoup de tables temporaires et le réglage de MySQL en modifiant le contenu des fichiers de configuration n'a pas aidé.

Détails

Le tableau détaille les paramètres que j'ai modifiés dans my.ini respectivement avant d'exécuter les requêtes. MySQL a été redémarré entre chaque test.

J'ai utilisé le my.ini trouvé dans la question d'origine comme modèle et j'ai ensuite changé la valeur des paramètres un par un selon le tableau ci-dessous.

J'ai utilisé JMeter pour générer 100 requêtes Web simultanées (car cela représentait notre utilisation) répétées 10 dix fois. Chaque Test se composait donc de 1000 requêtes au total. Cela a entraîné des appels de base de données ultérieurs. Cela a montré que MySQL créerait de nombreuses tables temporaires quels que soient les paramètres de configuration que nous avons modifiés.

+----+------------+-------+---------------+------------+
|Test|Parameter   |Value  |NumOfTempTables|Db Max Conn |
+----+------------+-------+---------------+------------+
| 1  |key_buffer_ | 25M   | 30682         | 29         |
|    |size        |       |               |            | 
+----+------------+-------+---------------+------------+
| 2  |key_buffer_ | 55M   | 30793         | 29         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 3  |key_buffer_ | 100M  | 30666         | 28         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 4  |key_buffer_ | 125M  | 30593         | 24         |
|    |size        |       |               |            | 
+----+------------+-------+---------------+------------+
| 5  |query_cache_| 100M  | 30627         | 32         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 6  |query_cache_| 250M  | 30761         | 26         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 7  |query_cache_| 500M  | 30864         | 83*        |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 8  |query_cache_| 1G    | 30706         | 75*        |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 9  |tmp_table_  | 125M  | 30724         | 31         |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 10 |tmp_table_  | 250M  | 30689         | 90*        |
|    |size        |       |               |            |
+----+------------+-------+---------------+------------+
| 11 |tmp_table_  | 500M  | 30792         | 28         |
|    |size        |       |               |            |  
+----+------------+-------+---------------+------------+
| 12 |Sort_buffer&| 256K  | 30754         | 28         |
|    |Join_buffer |       |               |            |
+----+------------+-------+---------------+------------+
| 13 |Sort_buffer&| 512K  | 30788         | 30         |
|    |Join_buffer |       |               |            | 
+----+------------+-------+---------------+------------+
| 14 |Sort_buffer&| 1M    | 30788         | 28         |
|    |Join_buffer |       |               |            | 
+----+------------+-------+---------------+------------+
| 15 |Sort_buffer&| 4M    | 30642         | 35         |
|    |Join_buffer |       |               |            |
+----+------------+-------+---------------+------------+
| 16 |innodb-     | 1G    | 30695         | 33         |
|    |buffer-     |       |               |            |
|    |pool-size   |       |               |            |
+----+------------+-------+---------------+------------+
| 17 |innodb-     | 2G    | 30791         | 28         |
|    |buffer-     |       |               |            |
|    |pool-size   |       |               |            | 
+----+------------+-------+---------------+------------+
| 18 |innodb-     | 3G    | 30719         | 34         |
|    |buffer-     |       |               |            |
|    |pool-size   |       |               |            |  
+----+------------+-------+---------------+------------+

* Moyenne de trois runs

Les images ci-dessous illustrent la quantité de mémoire et de CPU requise par le serveur de base de données pour les différentes configurations. Les lignes noires indiquent les valeurs minimales et maximales et les barres bleues indiquent les valeurs de début et de fin. La mémoire maximale était 4096M comme indiqué dans la question.

Memory UsageCPU Usage

13
user30431

Vous devez également vérifier si la taille de votre table temporaire en mémoire est limitée par la variable Taille maximale de la table de tas.

Lorsque vous utilisez le moteur de stockage MEMORY pour tables temporaires en mémoire , MySQL convertit automatiquement une table temporaire en mémoire en table sur disque si elle devient trop volumineuse.

Si l'espace requis pour créer une table temporaire dépasse tmp_table_size ou max_heap_table_size, MySQL crée une table sur disque dans le répertoire tmpdir du serveur. La taille maximale des tables temporaires en mémoire est définie par tmp_table_size ou max_heap_table_size valeur, la valeur la plus petite étant retenue.

0
martoncsukas