在“ALTER TABLE DROP PARTITION”时避免“等待表元数据锁定”?

qua*_*nta 6 mysql innodb partitioning alter-table locking

我有一些许多用户需要访问的表:

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) */
Run Code Online (Sandbox Code Playgroud)

当用户想要删除一个分区时ALTER TABLE v3_cam_date DROP PARTITION pcurrent_2013227,可能会导致很多事务处于以下Waiting for table metadata lock状态:

     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)))
Run Code Online (Sandbox Code Playgroud)

在不锁定的情况下完成此操作的有效方法是什么?

Rol*_*DBA 9

你所要求的是不可能的。无论存储引擎如何,任何类型的 DDL 都会锁定表。如果您必须从活动表中删除分区,您应该:

  1. 设置 MySQL 复制(如果您还没有这样做)
  2. v3_cam_date对 Slave执行所有涉及的SELECTs
  3. STOP SLAVE; 在奴隶
  4. ALTER TABLE ... DROP PARTITION在主上执行。
  5. 执行所有涉及v3_cam_date到 Master 的SELECTs
  6. START SLAVE;在奴隶上(复制ALTER TABLE ... DROP PARTITION到奴隶)

这可能是你唯一的办法。唯一的其他办法就是等待ALTER TABLE ... DROP PARTITION.

这种情况需要对应用程序进行一些干预。在您的应用程序中,您必须在 Master 上创建一个 Write DBVIP,并使用 Read DBVIP 和以下三 (3) 个选项之一:

选项1

  • 将读取 DBVIP 保留在从设备上

选项#2

  • 将 Read DBVIP 保留在 Master 上
  • 当您必须执行时ALTER TABLE,将读取 DBVIP 移至 Slave
  • ALTER TABLE已经完成,移动阅读DBVIP法师

选项 #3

  • 在负载均衡器上设置读取 DBVIP
  • 按需从 LoadBalanced DBVIP 中删除 Master

从长远来看,选项#1 似乎是最简单的方法。


小智 -7

我通过重新启动 MySQL 服务,然后尝试删除分区来解决这个问题。此后放置分区将生效。发生这种情况是因为二进制日志显然有一些尚未在该表中完成的内容。

我希望这些信息对您有所帮助。

  • 我不认为这就是问这个问题的人的目的。Quanta 正在寻求一种不会阻塞的解决方案(大概是为了让他的数据库的整体响应时间保持良好) - 重新启动服务将使其不可用并使所有当前事务失败。 (6认同)