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.
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?
Comment puis-je empêcher MySQL de manger ma mémoire?
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.
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
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
En regardant le my.ini
, J'ai deux suggestions
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;
É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.
É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.
Tu devrais être capable de
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.
Je suggérerais alors de configurer un RAM comme dossier cible pour vos tables temporaires
Jan 04, 2013
: Existe-t-il un moteur MySQL ou une astuce pour éviter d'écrire autant de tables temporaires sur le disque?Dec 17, 2012
: Pourquoi MySQL produit-il autant de fichiers MYD temporaires? (Instructions réelles)Nov 30, 2012
: Est-il mauvais de créer plusieurs tables temporaires mysql simultanément?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.
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.
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
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é.
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.
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.