Bloqueos MySQL mientras CREAR TABLA COMO SELECCIONAR


10

Estoy ejecutando la siguiente consulta (ficticia)

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

Supongamos que la consulta tarda 10 minutos en ejecutarse. Intentar actualizar los valores en las tablas a, b o c mientras se está ejecutando esperará a que la consulta anterior termine primero. Quiero evitar este bloqueo (la coherencia de los datos no es de interés). ¿Cómo puedo lograr eso?

Uso de: MySQL 5.1.41 y tablas de InnoDB

ps CONFIGURAR EL NIVEL DE AISLAMIENTO DE LA TRANSACCIÓN LEER SIN COMPROMISO no produce cambios en el comportamiento

Actualización Mientras se ejecuta la consulta, el resultado de SHOW ENGINE INNODB STATUS es el siguiente (he hecho una consulta muy lenta aquí a propósito)

=====================================
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
============================

Actualización 2

Al intentar actualizar b, c o d mientras se ejecuta la consulta, INNODB STATUS es lo siguiente:

=====================================
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
============================

Y existe la lista de proceso abierta real

Lista de procesos

Respuestas:


10

Veo esta consulta en tu 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 

Esta consulta me da escalofríos porque combina tres cosas en las que quizás no haya pensado:

  • InnoDB participa en función de su premisa inicial: Using: MySQL 5.1.41 and InnoDB Tables
  • MyISAM también está involucrado. ¿Por qué está involucrado MyISAM? ¡TODAS LAS TABLAS DE TEMPERATURA INTERNA SON MyISAM! La unión resultante es una tabla MyISAM que debe convertirse en InnoDB cuando se ha llenado la tabla temporal. ¿Cuál es el nivel de bloqueo predeterminado para las tablas MyISAM? Bloqueo de nivel de tabla.
  • DDL está involucrado ya que una tabla recién creada debe ser creada. Esa nueva tabla no se manifestaría hasta que se complete la tabla temporal, se convierta a InnoDB y finalmente se renombre 1_temp_foo.

Hay otro efecto secundario que vale la pena señalar. Cuando tu lo hagas

CREATE TABLE tblname AS SELECT ...

La tabla resultante no tiene índices.

Tengo algo que puede resultarle útil para evitar el problema del bloqueo. Implica hacer la tabla primero como una consulta separada, luego completarla. Hay dos opciones para hacer su tabla temporal:

OPCIÓN # 1 : intente crear la tabla con el mismo diseño

CREATE TABLE 1_temp_foo LIKE crm_companies;

Esto creará la tabla 1_temp_foopara tener exactamente los mismos índices y motor de almacenamiento que la tabla original crm_companies.

OPCIÓN # 2 : intente crear la tabla solo con el mismo motor de almacenamiento, pero sin índices.

CREATE TABLE 1_temp_foo SELECT * FROM crm_companies WHERE 1=2;
ALTER TABLE 1_temp_foo ENGINE=InnoDB;

Después de crear la tabla (de cualquier forma que elija), ahora puede completar la tabla de esta manera:

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
;

Ahora, esta consulta debería producir bloqueos de nivel de fila en aras de tener datos disponibles para lecturas repetibles. En otras palabras, esta es una consulta transaccional.

CONSIDERACIÓN

La OPCIÓN # 2 tiene ventajas sobre la OPCIÓN # 1

  • Ventaja n. ° 1 : si crm_companies tiene restricciones de clave externa, la OPCIÓN n. ° 1 no es realmente posible. Tendría que elegir la OPCIÓN # 2 por simplicidad.
  • Ventaja n. ° 2 : dado que la OPCIÓN n. ° 2 crea una tabla sin índices definidos por el usuario, la tabla debe cargarse más rápido que si la tabla se hubiera realizado a través de la OPCIÓN n. ° 1.

2

Además de establecer el nivel de aislamiento de transacción en LEÍDO COMPROMETIDO (o LEÍDO NO COMPROMETIDO), también debe tener su formato de registro binario establecido en MIXTO o FILA. La replicación basada en la DECLARACIÓN bloquea este tipo de declaración para asegurarse de que todo esté "seguro". También puede configurar innodb_locks_unsafe_for_binlog = 1 temporalmente, pero puede terminar con un esclavo que no está sincronizado de esa manera.

SET binlog_format = ROW;
CREATE TABLE ... SELECT ...

Lamentablemente, esto tampoco funciona :(
clops

1
¿Cuál es el resultado de SHOW ENGINE INNODB STATUS cuando se ejecuta la instrucción CREATE TABLE?
Aaron Brown

1
Además, asegúrese de estar usando LEER COMPROMISO, no LEER NO COMPROMETIDO. Podría encontrarse con este error que no se corrigió hasta 5.1.47 bugs.mysql.com/bug.php?id=48607
Aaron Brown el

1
Eso es extraño. ¿Hay claves foráneas? ¿Puedes publicar INNODB STATUS mientras intentas actualizar la fila? ¿Has probado esto en una versión más reciente de MySQL? (supongo que está utilizando 5.1.41 porque se envía con su distribución?)
Aaron Brown

1
¿Está seguro de que su tabla de usuarios es InnoDB? La actualización no aparece en la salida SHOW ENGINE INNODB STATUS y en la lista de procesos aparece como Bloqueada, que normalmente es el resultado de las tablas MyISAM. Me alegra que la respuesta de @ RolandoMySQLDBA haya resuelto tu problema, pero creo que hay algo más aquí.
Aaron Brown el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.