Skip to content

Instantly share code, notes, and snippets.

@methane
Created April 3, 2012 09:58
Show Gist options
  • Select an option

  • Save methane/2290769 to your computer and use it in GitHub Desktop.

Select an option

Save methane/2290769 to your computer and use it in GitHub Desktop.
古いレコード削除プログラム
#!/usr/bin/env python
# coding: utf-8
from __future__ import print_function
import datetime as dt
import os
import sys
import time
import logging
from ConfigParser import SafeConfigParser
import optparse
try:
import MySQLdb
except ImportError:
try:
import PyMySQL as MySQLdb
except ImportError:
print("Please install MySQL-python or PyMySQL.", file=sys.stderr)
sys.exit(1)
def connect(conf='~/.my.cnf', section='batch'):
"""
connect to MySQL from conf file.
"""
parser = SafeConfigParser()
parser.read([os.path.expanduser(conf)])
config = dict(parser.items(section))
params = {}
for n in ('host', 'user', 'db'):
if n in config:
params[n] = config[n]
if 'port' in config:
params['port'] = int(config['port'])
if 'password' in config:
params['passwd'] = config['password']
return MySQLdb.connect(**params)
def delete_old_log(con, tablename, days, blocksize=1000):
u"""ログテーブルから古いログを消す.
MySQL への接続 *con* を利用し、 *tablename* で指定された
テーブルから、 *days* で指定された日数よりも古いテーブルを
削除する. (*days* が 0 の時は、昨日以前のログを消す)
対象となるテーブルは、PK が整数の `id` というカラム名で
autoincrement されていて、 `created_at` というカラム名で
作成日時が記録されている必要がある.
*blocksize* は一括で削除する行数.
.. note:
制限として、 *blocksize* の間に消す日と消さない日の
区切りがあると、そのブロックにある古いレコードを消さない
まま終了している. (テーブルサイズ肥大化抑止が目的のため)
"""
date = dt.date.today() - dt.timedelta(days=days)
logging.info("delete records befor %s", date)
cur = con.cursor()
cur.execute("SELECT min(id),max(id) from %s" % (tablename,))
MIN, MAX = map(int, cur.fetchone())
for s in xrange(MIN, MAX, blocksize):
cur = con.cursor()
e = min(s + blocksize - 1, MAX)
cur.execute("SELECT created_at from %s WHERE id=%s" % (tablename, e))
d = cur.fetchone()[0]
if d is None:
raise ValueError("created_at is NULL: pk=%r" % (e,))
if d.date() >= date:
break
logging.debug("deleting %s-%s (%s)", s, e, d)
q = "DELETE LOW_PRIORITY FROM %s WHERE `id`<=%d" % (tablename, e)
logging.debug(q)
cur.execute(q)
con.commit()
time.sleep(1)
def main():
parser = optparse.OptionParser("%prog [OPTIONS] tablename")
parser.add_option('-d', '--days', type='int', default=30)
parser.add_option('-s', '--section', type='string', action="store", default='batch')
parser.add_option('-b', '--blocksize', type='int', default=1000)
parser.add_option('-v', '--verbose', action='store_const', const=1, default=0)
opts, args = parser.parse_args()
if not args:
parser.error("Only one tablename should be specified.")
loglevel = logging.DEBUG if opts.verbose else logging.INFO
logging.basicConfig(level=loglevel,
format="%(asctime)-15s %(levelname)9s %(message)s",
)
con = connect(section=opts.section)
for table in args:
logging.info("Start deleting old logs from: %s", table)
delete_old_log(con, table, opts.days)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment