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

27

Nous gérons un site (Moodle) que les utilisateurs trouvent actuellement lent. Je pense que j'ai trouvé le problème de la création de tables temporaires sur disque par MySQL. Je regarde la variable created_tmp_disk_tablesdans l'administration du serveur Mysql Workbench et le nombre augmente avec environ 50 tables / s. Après une utilisation de jours, created_tmp_disk_tablesest> 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é l' assistant de configuration de Percona pour générer un fichier de configuration, mais mon.ini n'a pas non plus résolu mon problème.

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?

modifier

J'ai activé le slow_queriesjournal 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é cela. Cela a réduit la vitesse à laquelle MySQL consomme de la mémoire, mais crée toujours des tables temporaires.

J'ai également vérifié que la key_buffer sizetaille est suffisamment grande. J'ai regardé la variable key_writes. Cela devrait être nul. Sinon, augmentez le . J'ai key_buffer_sizezéro key_readset zéro key_writesdonc je suppose que le key_buffer_sizeest assez grand.

J'ai augmenté le tmp_table_sizeet 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_passespar seconde dans la sortie SHOW GLOBAL STATUS, vous pouvez envisager d'augmenter la sort_buffer_sizevaleur. J'en ai eu 2 sort_merge_passesen une heure donc je considère que sort_buffer_sizec'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_diskreste est élevé. J'ai redémarré le serveur mysql après avoir changé la valeur et vérifié created_tmp_tables_on_diskaprè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                |
+-----------------------+-----------------------+

Information additionnelle

+--------------------+---------+
|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 de RAM, j'ai donc 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
user30431
la source
Les commentaires ne sont pas pour une discussion approfondie; cette conversation a été déplacée vers le chat .
Paul White dit GoFundMonica

Réponses:

16

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 que a JOINou a ORDER BYbesoin de plus 4M, il se paginera sur le disque en tant que table MyISAM.

Si vous ne pouvez pas vous connecter en tant que root@localhost, 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 sont sur le lecteur 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 lecteur C:, vous pouvez peut - être mapper des tables temporaires à disque D:en définissant tmpdir dans la my.inimanière suivante:

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 dans 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 disque RAM comme dossier cible pour vos tables temporaires

La création de la table temporaire se fera toujours, mais elle sera écrite sur la RAM plutôt que sur le disque. réduction des E / S disque.

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

SUGGESTION # 4

Je suggérerais de revoir 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 ceci à my.ini:

[mysqld]
tmpdir="T:\"

Un redémarrage de MySQL serait nécessaire, 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 comme @RaymondNijland l'a commenté, vous ne pouvez en aucun cas réduire le nombre de création de table temporaire. SUGGESTION #3et SUGGESTION #4proposent d'accélérer la création de tables temporaires et les E / S de tables temporaires comme seule alternative.

RolandoMySQLDBA
la source
13

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. Chacun Testconsistait donc en 1 000 demandes 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 minimale et maximale et les barres bleues indiquent les valeurs de début et de fin. La mémoire maximale était 4096Mcelle indiquée dans la question.

Utilisation de la mémoire L'utilisation du processeur

user30431
la source
Quel moteur de stockage utilisez-vous? MyiSAM? Si vous n'utilisez pas de tables MyISAM, il n'est pas significatif de s'appuyer sur key_buffer_size. si vous utilisez le moteur de stockage innodb, quelle est la taille de innodb_buffer_pool_size. Utilisez-vous query_cache?
kasi