web-dev-qa-db-fra.com

Éviter "En attente de la serrure de métadonnées de table" quand `Alter Table Drop Partition`?

J'ai des tables que de nombreux utilisateurs doivent accéder à:

mysql> show create table v3_cam_date\G
*************************** 1. row ***************************
       Table: v3_cam_date
Create Table: CREATE TABLE `v3_cam_date` (
  `campaignid` mediumint(9) NOT NULL DEFAULT '0',
  `totalclick` mediumint(9) unsigned NOT NULL DEFAULT '0',
  `totalview` int(11) unsigned NOT NULL DEFAULT '0',
  `realclick` mediumint(9) unsigned NOT NULL DEFAULT '0',
  `clickcharge` mediumint(9) unsigned NOT NULL DEFAULT '0',
  `viewcharge` int(11) unsigned NOT NULL DEFAULT '0',
  `uv` mediumint(9) unsigned NOT NULL DEFAULT '0',
  `uc` mediumint(9) unsigned NOT NULL DEFAULT '0',
  `dt` date NOT NULL DEFAULT '0000-00-00',
  `ctr` decimal(5,3) NOT NULL DEFAULT '0.000' COMMENT '=-1: meaning not available(N/A)',
  `moneyc` int(11) unsigned NOT NULL DEFAULT '0',
  `moneyv` int(11) unsigned NOT NULL DEFAULT '0',
  KEY `ix_campaignid_dt` (`campaignid`,`dt`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
/*!50100 PARTITION BY RANGE (TO_DAYS(dt))
(PARTITION p0 VALUES LESS THAN (0) ENGINE = InnoDB,
 PARTITION p01 VALUES LESS THAN (734502) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (734683) ENGINE = InnoDB,
 PARTITION p03 VALUES LESS THAN (734863) ENGINE = InnoDB,
 PARTITION p04 VALUES LESS THAN (734959) ENGINE = InnoDB,
 PARTITION p5 VALUES LESS THAN (735141) ENGINE = InnoDB,
 PARTITION p06 VALUES LESS THAN (735210) ENGINE = InnoDB,
 PARTITION MERGER_2013227 VALUES LESS THAN (735291) ENGINE = InnoDB,
 PARTITION pcurrent_2013227 VALUES LESS THAN (735292) ENGINE = InnoDB) */

Quand un utilisateur veut déposer une partition ALTER TABLE v3_cam_date DROP PARTITION pcurrent_2013227, il peut causer de nombreuses transactions dans le Waiting for table metadata lock Etat:

     Id: 31560182
   User: alice
   Host: 192.168.3.40:36132
     db: db
Command: Query
   Time: 806
  State: Waiting for table metadata lock
   Info: SELECT COUNT(DISTINCT A.`campaignid`)  INTO _campaigncomplete
        FROM `ox_campaigns` A 
        INNER JOIN `selfserving_users` B ON B.`user_id` = A.`uid`
        INNER JOIN `v3_cam_date` C ON C.`campaignid` = A.`campaignid`
        WHERE A.`revenue_type` = 5 AND A.`deleted` = 0 AND A.`expire` = DATE_ADD(    (SELECT `sys_date_cpc` FROM `000_sys_params_v4`) , INTERVAL 1 DAY) 
                AND A.`isExpired` = 0 AND IF( NAME_CONST('_permitid',3) = -1, 1=1, IF( NAME_CONST('_permitid',3) = 0, A.`uid` IN (SELECT C.`user_id` FROM `selfserving_users` C WHERE C.`groupid` =  NAME_CONST('_groupid',17) ) ,A.`uid` =  NAME_CONST('userid',5770)))

Quel est le moyen efficace d'accomplir cela sans verrouillage?

6
quanta

Ce que vous demandez est impossible. Indépendamment du moteur de stockage, DDL de tout type verrouille une table. Si vous devez supprimer une partition d'une table active, vous devriez:

  1. Configurer la réplication MySQL (si vous ne l'avez pas déjà fait)
  2. Effectuer toutes les sélectionnées impliquant v3_cam_date contre l'esclave
  3. STOP SLAVE; sur l'esclave
  4. Effectuer ALTER TABLE ... DROP PARTITION sur le maître.
  5. Effectuer toutes les sélectionnées impliquant v3_cam_date contre le maître
  6. START SLAVE; sur l'esclave (reproduit ALTER TABLE ... DROP PARTITION à l'esclave)

C'est probablement votre seul recours. Le seul autre recours est de simplement attendre le ALTER TABLE ... DROP PARTITION.

Cette situation nécessite une certaine intervention dans la demande. Dans votre application, vous devez créer un DBVIP d'écriture sur le maître et utiliser le DBVIP de lecture avec l'une des trois (3) options suivantes:

OPTION 1

  • Gardez la lecture DBVIP sur l'esclave

OPTION 2

  • Gardez la lecture DBVIP sur le maître
  • Quand vous devez faire un ALTER TABLE, déplacez la lecture DBVIP à l'esclave
  • Lorsque ALTER TABLE a été terminé, déplacez la lecture DBVIP au Master

Option n ° 3

  • Configuration Lire DBVIP sur un voleur
  • Supprimer le maître de la babaladed dbvip sur demande

L'option n ° 1 semble être la voie la plus simple à long terme.

8
RolandoMySQLDBA

Pour éviter ce type de problème, assurez-vous de commettre ou de retourner votre transaction.

en raison de la table Select est verrouillé en mode partagé.

Voici exemple

session1 > start transaction;
Query OK, 0 rows affected (0.00 sec)

session1 > select * from test order by id;
+----+------+
| id | a    |
+----+------+
|  1 | x  |
|  2 | y  |
+----+------+
2 rows in set (0.00 sec)

session2 > ALTER TABLE test add column c char(32) default 'xyz';

session3 > show processlist;
+----+----------+-----------+------+---------+------+---------------------------------+-------------------------------------------------------------+
| Id | User     | Host      | db   | Command | Time | State                           | Info                                                        |
+----+----------+-----------+------+---------+------+---------------------------------+-------------------------------------------------------------+
|  1 | sameer | localhost | test | Sleep   |  253|                                 | NULL                                                        |
|  2 | sameer | localhost | test | Query   |    3 | Waiting for table metadata lock | ALTER TABLE test add column c char(32) default 'xyz' |
|  3 | sameer | localhost | test | Query   |    0 | NULL                            | show processlist                                            |
+----+----------+-----------+------+---------+------+---------------------------------+-------------------------------------------------------------+
3 rows in set (0.00 sec)


session1 > rollback;
Query OK, 0 rows affected (0.00 sec)

session2 > ALTER TABLE test add column c char(32) default 'xyz';
Query OK, 2 rows affected (46.32 sec)
Records: 2  Duplicates: 0  Warnings: 0

Vous pouvez tuer toutes les sessions qui sont en mode veille ou la session de sortie d'où sélectionnez l'exécution.

2
Sameer Kumar