需求

现在有个这么一个需求,mysql中有个表,数据增长的很快,但是呢这个数据有效期也就是1个月,一个月以前的记录不太重要了,但是又不能删除。为了保证这个表的查询速度,需要一个简单的备份表,把数据倒进去。

代码

于是我写了一个小脚本,用来做定时任务,把这个表某段时间的数据备份到备份表中,核心就是个简单的sql。

原始表radius 备份的表为 radius2015

#!/usr/bin/python2.7
# -*- coding: utf-8 -*-
#python2.7x
#authror: orangleliu
#备份radius中的上网记录表,每个月备份一次,原始表中保留一份数据
#使用同一个数据库中的一个不同表名的表备份

import time
import datetime
import logging
from datetime import timedelta

import MySQLdb
import MySQLdb.cursors

logging.basicConfig(format='%(asctime)s %(levelname)s - \
    %(message)s')
logger = logging.getLogger('backup')
logger.setLevel(logging.DEBUG)

#数据库配置
DBPARAMS = {
    "host":"127.0.0.1",
    "user":"root",
    "password":"",
    "database":"test",
    "charset": ""
}

#这里使用select into 来备份,数据校验对比记录数,一个月大概100w条数据
#radacct2015
#检查表,检查重传,备份,校验

create_table_sql = '''
CREATE TABLE `{0}` (
  `radacctid` bigint(21) NOT NULL AUTO_INCREMENT,
  `acctsessionid` varchar(64) NOT NULL DEFAULT '',
  `acctuniqueid` varchar(32) NOT NULL DEFAULT '',
  `username` varchar(64) NOT NULL DEFAULT '',
  `groupname` varchar(64) NOT NULL DEFAULT '',
  `realm` varchar(64) DEFAULT '',
  `nasipaddress` varchar(15) NOT NULL DEFAULT '',
  `nasportid` varchar(15) DEFAULT NULL,
  `nasporttype` varchar(32) DEFAULT NULL,
  `acctstarttime` int(11) DEFAULT NULL,
  `acctupdatetime` int(11) DEFAULT NULL,
  `acctstoptime` int(11) DEFAULT NULL,
  `acctinterval` int(12) DEFAULT NULL,
  `acctsessiontime` int(12) unsigned DEFAULT NULL,
  `acctauthentic` varchar(32) DEFAULT NULL,
  `connectinfo_start` varchar(50) DEFAULT NULL,
  `connectinfo_stop` varchar(50) DEFAULT NULL,
  `acctinputoctets` bigint(20) DEFAULT NULL,
  `acctoutputoctets` bigint(20) DEFAULT NULL,
  `calledstationid` varchar(50) NOT NULL DEFAULT '',
  `callingstationid` varchar(50) NOT NULL DEFAULT '',
  `acctterminatecause` varchar(32) NOT NULL DEFAULT '',
  `servicetype` varchar(32) DEFAULT NULL,
  `framedprotocol` varchar(32) DEFAULT NULL,
  `framedipaddress` varchar(15) NOT NULL DEFAULT '',
  PRIMARY KEY (`radacctid`),
  UNIQUE KEY `acctuniqueid` (`acctuniqueid`),
  KEY `username` (`username`),
  KEY `framedipaddress` (`framedipaddress`),
  KEY `acctsessionid` (`acctsessionid`),
  KEY `acctsessiontime` (`acctsessiontime`),
  KEY `acctstarttime` (`acctstarttime`),
  KEY `acctinterval` (`acctinterval`),
  KEY `acctstoptime` (`acctstoptime`),
  KEY `nasipaddress` (`nasipaddress`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
'''

back_sql = '''
INSERT INTO {0}
SELECT *
FROM {1}
WHERE acctstarttime < UNIX_TIMESTAMP(
   STR_TO_DATE('{2}', '%Y-%m-%d')
) AND acctstarttime >= UNIX_TIMESTAMP(
   STR_TO_DATE('{3}', '%Y-%m-%d')
)'''

count_sql = """
SELECT count(*) FROM {0} WHERE 1=1 AND
acctstarttime < UNIX_TIMESTAMP(
   STR_TO_DATE('{1}', '%Y-%m-%d')
) AND acctstarttime >= UNIX_TIMESTAMP(
   STR_TO_DATE('{2}', '%Y-%m-%d')
)
"""

#date tools
def get_year(month):
    #month like 201505
    return datetime.datetime.strptime(month, "%Y%m").year

def get_month_firstday_str(month):
    return datetime.datetime.strptime(month,"%Y%m").\
                                        strftime("%Y-%m-%d")

def get_next_month_firstday_str(month):
    month_firstday = datetime.datetime.strptime(month,"%Y%m")
    monthnum = month_firstday.month
    return "{0}-{1}-{2}".format(
            month_firstday.year if monthnum < 12 else \
                                 month_firstday.year + 1,
            monthnum + 1 if monthnum < 12 else 1, 1)

class DBConn(object):
    __CONFIG = {
        'default': {
            'host': "",
            'user': "",
            'database': "",
            'password': "",
            'charset': "",
        }
    }

    def __init__(self, connname='', connconfig={}):
        if connconfig:
            self.connconfig = connconfig
        else:
            connname = connname or 'default'
            self.connconfig = self.__CONFIG.get(connname, 'default')
        self.conn = None

    def __enter__(self):
        try:
            self.conn = MySQLdb.connect(
                user=self.connconfig['user'],
                db=self.connconfig['database'],
                passwd=self.connconfig['password'],
                host=self.connconfig['host'],
                use_unicode=True,
                charset=self.connconfig['charset'] or "utf8",
                #cursorclass=MySQLdb.cursors.DictCursor
                )

            return self.conn
        except Exception, e:
            print str(e)
            return None

    def __exit__(self, exe_type, exe_value, exe_traceback):
        if exe_type and exe_value:
            print '%s: %s' % (exe_type, exe_value)
        if self.conn:
            self.conn.close()

class RadiusBackup(object):
    def __init__(self, month, conn):
        self.conn = conn
        self.cursor = conn.cursor()
        self.month = month
        self.year = get_year(month)
        self.month_firstday = get_month_firstday_str(month)
        self.next_month_firstday = get_next_month_firstday_str(month)
        self.tablename = "radacct{0}".format(self.year)
        self.stable = "radacct"

    def check_table_exist(self):
        check_table_sql = "SHOW TABLES LIKE '{0}'".format(
                            self.tablename)
        self.cursor.execute(check_table_sql)
        res = self.cursor.fetchall()
        return True if len(res) > 0 else False

    def create_backup_table(self):
        sql = create_table_sql.format(self.tablename)
        self.cursor.execute(sql)
        logger.info(u"开始创建备份表 {0}".format(self.tablename))

    def check_datas_count(self, tablename):
        sql = count_sql.format(tablename, self.next_month_firstday,
                    self.month_firstday)
        logger.debug(sql)
        self.cursor.execute(sql)
        res = self.cursor.fetchone()
        return res[0]

    def check_before(self):
        flag = False
        #check table
        if not self.check_table_exist():
            self.create_backup_table()
            if self.check_table_exist() == False:
                logger.error(u"无法找到备份表 exit")
                return flag
        #check datas
        if self.check_datas_count(self.tablename) > 0:
            return flag
        else:
            return True

    def backup_datas(self):
        sql = back_sql.format(self.tablename, self.stable,
                self.next_month_firstday, self.month_firstday)
        logger.debug(sql)
        self.cursor.execute(sql)
        self.conn.commit()

    def check_after(self):
        snum = self.check_datas_count(self.stable)
        bnum = self.check_datas_count(self.tablename)
        if snum > 0 and (snum == bnum):
            logger.info(u"备份成功")
            return snum, True
        else:
            return -1, False

    def backup_handler(self):
        if self.check_before():
            logger.info(u"检查完毕,开始备份数据")
            self.backup_datas()
            logger.info(u"开始备份")
            num, flag = self.check_after()
            logger.info(u"本次备份{0} 数据 {1}条".format(self.month, num))
        else:
            logger.info(u"数据已经有备份,请检查")

if __name__ == "__main__":
    month = "201504"

    with DBConn(connconfig=DBPARAMS) as dbconn:
        if dbconn:
            backup = RadiusBackup(month, dbconn)
            backup.backup_handler()
        else:
            logger.error("can not connect to db")

本文出自 “orangleliu笔记本” 博客,转载请务必保留此出处http://blog.csdn.net/orangleliu/article/details/46650875 作者orangleliu 采用署名-非商业性使用-相同方式共享协议

[Mysql]备份同库中一张表的历史记录 insert into ..select的更多相关文章

  1. mysql查询一个库中有多少张表

    SELECT COUNT(*) TABLES, table_schema FROM information_schema.TABLES  WHERE table_schema = 'palm_2_0_ ...

  2. 查看Sql Server库中某张表的结构

    --快速查看表结构(比较全面的) SELECT CASE WHEN col.colorder = THEN obj.name ELSE '' END AS 表名, col.colorder AS 序号 ...

  3. 从MySQL全库备份中恢复某个库和某张表【转】

    从MySQL全库备份中恢复某个库和某张表 一.全库备份-A [root@mha2 backup]#mysqldump -uroot -p123456 --default-character-set=u ...

  4. 获取一个表中的字段总数(mysql) Navicat如何导出Excel格式表结构 获取某个库中的一个表中的所有字段和数据类型

    如何获取一个表中的字段总数 1.function show columns from 表明: 结果 : 2.functiuon select count(*) from INFORMATION_SCH ...

  5. sql 从一个库中取某个表的数据导入到另一个库中相同结构的表中

    sql 2008 从一个库中把 某个表中的数据导入到另一个库中的具有相同结构的表中 use 库1 go insert into  库1.dbo.表1  select * from  库2.dbo.表1 ...

  6. SQL-49 针对库中的所有表生成select count(*)对应的SQL语句

    题目描述 针对库中的所有表生成select count(*)对应的SQL语句CREATE TABLE `employees` (`emp_no` int(11) NOT NULL,`birth_dat ...

  7. #mysql查询特定数据库中的所有表名

    #mysql查询特定数据库中的所有表名select table_namefrom information_schema.tableswhere table_schema='smbms' and tab ...

  8. 从MySQL全库备份中恢复某个库和某张表

    在Mysqldump官方工具中,如何只恢复某个库呢? 全库备份 [root@HE1 ~]# mysqldump -uroot -p --single-transaction -A --master-d ...

  9. MySQL只恢复某个库或某张表

    在Mysqldump官方工具中,如何只恢复某个库呢? 全库备份 [root@HE1 ~]#mysqldump -uroot -p --single-transaction -A --master-da ...

随机推荐

  1. BZOJ2989 数列(二进制分组)

    这题其实可以cdq分治做,但是如果强制在线的话,这里有个牛逼方法叫二进制分组. 它的基本思想是把修改操作按二进制分组,遇到修改就在尾部加一个,并与之前的合并,比如之前有23(16+4+2+1)个,加了 ...

  2. Mysql--存储引擎(MyISam & InnoDB)

    Mysql 系列文章主页 =============== 查看 Mysql 支持的存储引擎: show engines; 查看当前数据库使用的存储引擎: show variables like '%s ...

  3. js修改伪类元素样式

    <style type="text/css"> .htmlbox_close::before, .htmlbox_close::after { content: ''; ...

  4. 40. Combination Sum II(midum, backtrack, 重要)

    Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in ...

  5. Microsoft SQL server2017初次安装与使用记录

    Microsoft SQL server2017初次安装与使用记录 学校数据库课程以Microsoft SQL server为例, 由于老师给的软件版本和我的window10不兼容,选择官网的最新版2 ...

  6. Git-gitblit-Tortoisegit 搭建Windows Git本地服务器

    1.Gitblit安装 1.1.Gitblit简介 Git在版本控制领域可谓是深受程序员喜爱.对于开源的项目,可以免费托管到GitHub上面,相当的方便.但是私有项目托管到GitHub会收取相当昂贵的 ...

  7. EntityFramework Core 自动绑定模型映射

    笔者最近在和同事共同开发项目时,需要从他们提供的包含数据库实体类型的类库中读取实体信息绑定到自己的项目中(但是都在同一个解决方案里),所以很直接的一种方式就是把项目中所有的实体都以 public Db ...

  8. 浏览器加载和渲染html的顺序(html/css/js)

    最近在学习前端的技术,把html.js.css的基础知识看了看.感觉越看越觉得前端并不比后端容易,技术含量还是相当大的.今天突然想弄明白浏览器到底是怎么加载和渲染html的?html中的DOM.js文 ...

  9. JVM三种垃圾收集算法思想及发展过程

    JVM垃圾收集算法的具体实现有很多种,本文只是介绍实现这些垃圾收集算法的三种思想和发展过程.所有的垃圾收集算法的具体实现都是遵循这三种算法思想而实现的. 1.标记-清除算法 标记-清除(Mark-Sw ...

  10. Gi之(二)基础命令

    三个工作区域 使用Git之前,首先要弄清Git的三个管理区域,有助于理解Git的运行原理,以及每个Git命令对文件造成的影响. 对于任何一个文件,在本地的Git内部都有三种状态: l   已修改(mo ...