大表百万条以上记录非主键索引删除大量数据的操作方法

众所周知,上百万表数据类似上述写法,哪怕where条件命中索引,执行时间也不会低于10分钟;考虑对数据的操作会引起两表的排他锁,造成业务被暂停!从服务器资源的影响:IOPS升高,IO争用造成CPU等待(高CPU);删除表存在的大量空间碎片,造成的空间浪费及性能低下

这种需求可以采用中间表rename方法,将要保留的数据写入中间表,写入完成后将原表删除,并将中间表改名为原始表;

具体操作步骤如下:

1.SHOW CREATE TABLE ooo_scrm_customer;

 

2.创建同ooo_scrm_customer表结构一样的新表:_ooo_scrm_customer_new 

REATE TABLE _ooo_scrm_customer_new (

`id` int(11) NOT NULL AUTO_INCREMENT,

    .....

    .....

    .....

PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.创建增删改触发器(主要用于主表向中间表写数据时,业务方请求修改的数据要一起同步到中间表)

CREATE TRIGGER `ooo_scrm_customer_del` AFTER DELETE ON ooo_scrm_customer FOR EACH ROW DELETE IGNORE FROM _ooo_scrm_customer_new WHERE _ooo_scrm_customer_new.`id` <=> OLD.`id`

CREATE TRIGGER `ooo_scrm_customer_upd` AFTER UPDATE ON ooo_scrm_customer FOR EACH ROW REPLACE INTO _ooo_scrm_customer_new(`id`, `其他列`) VALUES (NEW.`id`, NEW.`其他列`)

CREATE TRIGGER `ooo_scrm_customer_ins` AFTER INSERT ON ooo_scrm_customer FOR EACH ROW REPLACE INTO _ooo_scrm_customer_new(`id`, `其他列`) VALUES (NEW.`id`, NEW.`其他列`)

4.将要保留的数据写入中间表

INSERT LOW_PRIORITY IGNORE INTO _ooo_scrm_customer_new (`id`, `其他列`) SELECT `id`, `其他列` FROM ooo_scrm_customer LOCK IN SHARE MODE #where 条件优化,按分批执行思想,稳步执行!

5.优化中间表

ANALYZE TABLE_ooo_scrm_customer_new 

6.改名并删除操作记录

RENAME TABLE ooo_scrm_customer TO _ooo_scrm_customer_old, _ooo_scrm_customer_new TO ooo_scrm_customer

DROP TRIGGER IF EXISTS `mysqlcheck`.`ooo_scrm_customer_del`

DROP TRIGGER IF EXISTS `mysqlcheck`.`ooo_scrm_customer_upd`

DROP TRIGGER IF EXISTS `mysqlcheck`.`ooo_scrm_customer_ins`

其他应用案例

该思想起源facebook的mysql path,也是大名鼎鼎pt-online-schema-change工具的实现原理。

可应用于在线改表结构,在线修改表数据,原则上来讲可以实现秒级别的表锁定,对业务的0伤害

同学们在程序实现时还可灵活的使用其他方法:

SET SESSION lock_wait_timeout=60;SET SESSION innodb_lock_wait_timeout=1;SET SESSION wait_timeout=10000

(innodb_lock_wait_timeout指的是事务等待获取资源等待的最长时间,超过这个时间还未分配到资源则会返回应用失败;)

如有类似需求,请将该思想运用到你们的项目中吧。

OVER!!

时间: 2024-10-11 22:02:27

大表百万条以上记录非主键索引删除大量数据的操作方法的相关文章

获取呈现在格表(table)记录的主键

用mouse点击表格(table)的行或是批定列,获取记录的主键值.在ASP.NET的MVC应用程序中,已经没有办法象ASP.NET的Data控件一样,如GridView,DataList和Repeater控件好找到记录记键值了.下面的示例中,Insus.NET演示,如何获取呈现在格表(table)记录的主键.打开以前练习的例子: 先来演示,点击行中任何一列,获取: 实时演示: 如果,我们想只能点击第一列,才去获取记录的主键值,也就是说,指定点击某一列,这样的话,我们改一下jQuery代码: 看

普通索引、唯一索引、主索引、外键索引、复合索引、非主码索引、聚集主码(聚集索引)、单列索引、多列索引

强烈建议看了第一个参考文献再来看这个篇博文,因为此处不准备讲底层数据结构的实现. 索引:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构.其表达的是存储引擎的范畴,也就是说只有在存储引擎级别谈索引才有意义.MyISAM.InnoDB.Memory等.此处单纯就InnoDB存储引擎讨论. B-TREE.B+TREE数据结构. 在数据之外,数据库系统还维护着满足特定查找算 法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这

yii之relations关联非主键

yii的relations里self::BELONGS_TO默认是用当前指定的键跟关联表的主键进行join,例如: return array('reply' => array(self::BELONGS_TO, 'BookPostReply', 'postid'),);默认生成的sql是 on id = postid,id是BookPostReply的主键.但今天我遇到的需求却是需要生成 on BookPostReply.postid = t.postid,不去关联主键,而且关联其中一个字段的值

MyBatis 插入时返回刚插入记录的主键值

MyBatis 插入时返回刚插入记录的主键值 一.要求: 1.数据库表中的主键是自增长的,如:id: 2.获取刚刚插入的记录的id值: 二.源代码: 1.User.java 1 package cn.com.zfc.model; 2 3 public class User { 4 5 private Integer id; 6 private String name; 7 private String password; 8 9 public Integer getId() { 10 retur

Oracle通过主键id删除记录很慢

问题描述: Oracle通过主键id删除2000条记录很慢,需要花费十二分钟. 解决过程: 1.首先查看SQL的执行计划,执行计划正常,cost只有4,用到了主键索引. 2.查看等待事件, select * from v$session_wait where sid = 507 显示的event是db file sequential read,也没有异常. 3.查看统计信息是否正常 select * from user_tables where table_name = ''; 经检测,统计信息

外键关联非主键id时-hbm.xml配置,及其分页查询DaoImpl

表关联时,外键关联非主键id时-hbm.xml配置: (由于hibernate默认为关联主键查询,故需要配置相关hql语句的属性) <many-to-one name="areas" class="com.hnqy.entity.Areas" fetch="select" property-ref="areaid" foreign-key="areaid"> <column name=&q

关于hibernate非主键多对一关联

一直以来,用hibernate做多对一时,关联的都是主键,今天,同事设计的表,关联的却不是主键,这下麻烦了,hibernate的many-to-one默认关联的都是主键,原来,hibernate提供了非主键的关联,即只要加一个property-ref即可,如: <many-to-one name="dept" class="Dept" property-ref="dept_no"> <column name="dept

MyBatis+MySQL 返回插入记录的主键ID

今天用到了多个表之间的关系,另一个表中的一个字段要以第一个表的主键作为外键. 下面说两种方法,MyBatis+MySQL 返回插入记录的主键ID: 第一种: <insert id="insertAndGetId" useGeneratedKeys="true" keyProperty="userId" parameterType="com.chenzhou.mybatis.User"> insert into us

MyBatis返回插入记录的主键

如果想插入一条记录之后,立刻对其进行其他操作,这时候就需要获取记录的主键(通常是ID),MyBatis有以下方式处理. Dao层的接口定义如下: void importUser(@Param( "user" ) User user); 注意:这里不能因为要返回主键而定义接口的返回值类型为String或者int,会报错. xml配置文件: <insert id= "importUser" useGeneratedKeys = "true" k