Locks MySQL tandis que CREATE TABLE AS SELECT
Question
Je suis en cours d'exécution de la requête suivante (fictif)
CREATE TABLE large_temp_table AS
SELECT a.*, b.*, c.*
FROM a
LEFT JOIN b ON a.foo = b.foo
LEFT JOIN c ON a.bar = c.bar
Supposons que la requête prend 10 minutes pour exécuter. Essayer de valeurs de mise à jour dans les tableaux a, b ou c pendant son exécution attendra la requête ci-dessus pour terminer premier. Je veux éviter ce blocage (cohérence des données ne sont pas d'intérêt). Comment puis-je y parvenir?
Utilisation: MySQL 5.1.41 et les tables InnoDB
p.s. SET TRANSACTION ISOLEMENT NIVEAU READ UNCOMMITTED; donne aucun changement de comportement
Mise à jour Bien que la requête est en cours d'exécution, la sortie de SHOW STATUS MOTEUR InnoDB est le suivant (je l'ai fait une requête très lente ici fin)
=====================================
120323 15:26:29 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 8 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 1470, signal count 1468
Mutex spin waits 0, rounds 7525, OS waits 112
RW-shared spins 803, OS waits 364; RW-excl spins 1300, OS waits 959
------------
TRANSACTIONS
------------
Trx id counter 0 3145870
Purge done for trx's n:o < 0 3141943 undo n:o < 0 0
History list length 22
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, OS thread id 2958192640
MySQL thread id 7942, query id 69073 localhost root
SHOW ENGINE INNODB STATUS
---TRANSACTION 0 3145869, ACTIVE 20 sec, OS thread id 2955325440, thread declared inside InnoDB 343
mysql tables in use 1, locked 1
6 lock struct(s), heap size 1024, 162 row lock(s)
MySQL thread id 7935, query id 69037 localhost root Copying to tmp table
CREATE TABLE 1_temp_foo AS
SELECT SQL_NO_CACHE
a.*
FROM
crm_companies AS a
LEFT JOIN users b ON a.zipcode = b.uid
LEFT JOIN calc_base_materials c ON a.zipcode = c.material_id
LEFT JOIN calc_base_material_langtext d ON a.zipcode = d.material_id
LEFT JOIN crm_people e ON a.zipcode = e.telephone1_number
ORDER BY a.country, a.name1
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
Pending normal aio reads: 0, aio writes: 0,
ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
27579 OS file reads, 613 OS file writes, 392 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 5, seg size 7,
0 inserts, 0 merged recs, 0 merges
Hash table size 34679, node heap has 9 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
---
LOG
---
Log sequence number 1 2030837110
Log flushed up to 1 2030837110
Last checkpoint at 1 2030837110
0 pending log writes, 0 pending chkp writes
231 log i/o's done, 0.00 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 21060366; in additional pool allocated 1048576
Dictionary memory allocated 2897304
Buffer pool size 512
Free buffers 0
Database pages 503
Modified db pages 0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 36022, created 166, written 504
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000
--------------
ROW OPERATIONS
--------------
1 queries inside InnoDB, 0 queries in queue
1 read views open inside InnoDB
Main thread id 2957578240, state: waiting for server activity
Number of rows inserted 2022, updated 7, deleted 13, read 528536
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 8.00 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================
Mise à jour 2
Lors d'une tentative de mise à jour soit b, c ou d alors que la requête est en cours d'exécution STATUS INNODB est le suivant:
=====================================
120323 16:12:58 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 27 seconds
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 2959, signal count 2957
Mutex spin waits 0, rounds 27587, OS waits 426
RW-shared spins 1321, OS waits 516; RW-excl spins 2578, OS waits 1855
------------
TRANSACTIONS
------------
Trx id counter 0 3145998
Purge done for trx's n:o < 0 3145994 undo n:o < 0 0
History list length 0
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 0 0, not started, OS thread id 2958602240
MySQL thread id 7990, query id 69621 localhost root
SHOW INNODB STATUS
---TRANSACTION 0 3145997, ACTIVE 35 sec, OS thread id 2955325440, thread declared inside InnoDB 227
mysql tables in use 1, locked 0
MySQL thread id 7984, query id 69594 localhost root Copying to tmp table
CREATE TABLE 1_temp_foo AS
SELECT SQL_NO_CACHE
a.*
FROM
crm_companies AS a
LEFT JOIN users b ON a.zipcode = b.uid
LEFT JOIN calc_base_materials c ON a.zipcode = c.material_id
LEFT JOIN calc_base_material_langtext d ON a.zipcode = d.material_id
LEFT JOIN crm_people e ON a.zipcode = e.telephone1_number
ORDER BY a.country, a.name1
Trx read view will not see trx with id >= 0 3145998, sees < 0 3145998
--------
FILE I/O
--------
I/O thread 0 state: waiting for i/o request (insert buffer thread)
I/O thread 1 state: waiting for i/o request (log thread)
I/O thread 2 state: waiting for i/o request (read thread)
I/O thread 3 state: waiting for i/o request (write thread)
Pending normal aio reads: 0, aio writes: 0,
ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
Pending flushes (fsync) log: 0; buffer pool: 0
54447 OS file reads, 1335 OS file writes, 509 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 5, seg size 7,
584 inserts, 584 merged recs, 4 merges
Hash table size 34679, node heap has 1 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
---
LOG
---
Log sequence number 1 2060137545
Log flushed up to 1 2060137545
Last checkpoint at 1 2060137545
0 pending log writes, 0 pending chkp writes
338 log i/o's done, 0.00 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 20799534; in additional pool allocated 1047808
Dictionary memory allocated 2897304
Buffer pool size 512
Free buffers 0
Database pages 511
Modified db pages 0
Pending reads 0
Pending writes: LRU 0, flush list 0, single page 0
Pages read 70769, created 661, written 3156
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000
--------------
ROW OPERATIONS
--------------
1 queries inside InnoDB, 0 queries in queue
2 read views open inside InnoDB
Main thread id 2957578240, state: waiting for server activity
Number of rows inserted 2022, updated 66643, deleted 13, read 626517
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 7.59 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================
Et il y a la liste de processus ouvert réel
La solution
Je vois cette requête dans votre SHOW INNODB STATUS\G
CREATE TABLE 1_temp_foo AS
SELECT SQL_NO_CACHE
a.*
FROM
crm_companies AS a
LEFT JOIN users b ON a.zipcode = b.uid
LEFT JOIN calc_base_materials c ON a.zipcode = c.material_id
LEFT JOIN calc_base_material_langtext d ON a.zipcode = d.material_id
LEFT JOIN crm_people e ON a.zipcode = e.telephone1_number
ORDER BY a.country, a.name1
Cette requête me donne la chair de poule, car il combine trois choses que vous ne pouvez pas avoir pensé:
- InnoDB est impliqué en fonction de votre prémisse initiale:
Using: MySQL 5.1.41 and InnoDB Tables
- MyISAM est également impliqué. Pourquoi est-MyISAM impliqué? TOUS LES INTERNES TABLES SONT TEMP MyISAM !!! La jointure résultante est une table MyISAM qui doit être converti en InnoDB lorsque la table temporaire a été peuplée. Quel est le niveau de verrouillage par défaut pour les tables MyISAM? Tableau niveau de verrouillage.
- est impliqué depuis DDL une table nouvellement créée doit être mis en existence. ne serait pas manifeste que la nouvelle table jusqu'à ce que la table temporaire est peuplée, converti en InnoDB, et finalement rebaptisé
1_temp_foo
.
Il y a un autre effet secondaire intéressant de noter. Lorsque vous faites
CREATE TABLE tblname AS SELECT ...
Le tableau résultant n'a pas d'index.
J'ai quelque chose que vous pourriez trouver utile de contourner le problème de verrouillage. Il consiste à faire la table d'abord comme une requête séparée, puis peuplant. Il y a deux options pour rendre votre table temporaire:
# 1 : Essayez de créer la table avec la même mise en page
CREATE TABLE 1_temp_foo LIKE crm_companies;
Cela va créer la table 1_temp_foo
pour avoir exactement le même index et moteur de stockage comme le crm_companies
de table d'origine.
# 2 :. Essayez de créer la table avec le même moteur de stockage uniquement, mais pas d'index
CREATE TABLE 1_temp_foo SELECT * FROM crm_companies WHERE 1=2;
ALTER TABLE 1_temp_foo ENGINE=InnoDB;
Après avoir créé la table (la façon que vous choisissez), vous pouvez maintenant remplir la table comme ceci:
INSERT INTO 1_temp_foo
SELECT SQL_NO_CACHE a.*
FROM
crm_companies AS a
LEFT JOIN users b ON a.zipcode = b.uid
LEFT JOIN calc_base_materials c ON a.zipcode = c.material_id
LEFT JOIN calc_base_material_langtext d ON a.zipcode = d.material_id
LEFT JOIN crm_people e ON a.zipcode = e.telephone1_number
ORDER BY a.country, a.name
;
Maintenant, cette requête devrait produits verrous de niveau ligne pour le plaisir d'avoir des données disponibles pour des lectures répétables. En d'autres termes, il est une requête transactionnelle.
CAVEAT
OPTION # 2 présente des avantages sur OPTION # 1
- Avantage # 1 : Si crm_companies a des contraintes de clé étrangère, OPTION # 1 n'est pas vraiment possible. Vous devez choisir OPTION # 2 pour des raisons de simplicité.
- Avantage # 2 :. Depuis OPTION # 2 crée une table sans index définis par l'utilisateur, la table devrait se charger plus rapidement que si la table ont été faites via l'option # 1
Autres conseils
En plus de définir le niveau d'isolation de transaction à READ COMMITTED (ou lecture non validée), vous devez avoir également votre jeu de format de journal binaire mixte ou ROW. DÉCLARATION réplication basée bloque ce type de déclaration pour vous assurer que tout est « sûr ». Vous pouvez également définir innodb_locks_unsafe_for_binlog = 1 temporairement, mais vous pourriez finir avec un esclave qui est désynchronisée cette façon.
SET binlog_format = ROW;
CREATE TABLE ... SELECT ...