patch 4.0
This commit is contained in:
258
script/plan/outline.py
Executable file
258
script/plan/outline.py
Executable file
@ -0,0 +1,258 @@
|
||||
#!/usr/bin/python
|
||||
# coding=utf8
|
||||
import os
|
||||
import argparse
|
||||
import mysql.connector
|
||||
import sys
|
||||
|
||||
class Config:
|
||||
pass
|
||||
|
||||
g_config = Config()
|
||||
|
||||
class Stat:
|
||||
def reset(self):
|
||||
self.db_count = 0
|
||||
self.outline_count = 0
|
||||
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
||||
|
||||
g_stat = Stat()
|
||||
|
||||
class ImportStat:
|
||||
def reset(self):
|
||||
self.succ_db_count = 0
|
||||
self.fail_db_count = 0
|
||||
self.succ_outline_count = 0
|
||||
self.fail_outline_count = 0
|
||||
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
||||
|
||||
g_import_stat = ImportStat()
|
||||
|
||||
#参数
|
||||
#-h -P -u -p -t -i -d
|
||||
#如果-t没指定就是所有租户
|
||||
#
|
||||
#-d 表示dump
|
||||
#-i 表示import
|
||||
|
||||
#查询__all_server表。获取有多少台server, 设置并发度
|
||||
#设置查询超时时间
|
||||
#查询GV$OB_PLAN_CACHE_PLAN_STAT表获取outline_data
|
||||
#
|
||||
#select sql_id, sql_text, outline_data from GV$OB_PLAN_CACHE_PLAN_STAT。检查sql_id是否有冲突,outline_data是否有冲突//获取对应的database。
|
||||
#
|
||||
#dump成outline语句, 生成对应的database。
|
||||
#生成outline语句
|
||||
|
||||
def get_connect():
|
||||
return mysql.connector.connect(host = g_config.host, port = g_config.port, user = g_config.username, password = g_config.password)
|
||||
|
||||
def get_real_db_id(tenant_id, db_id):
|
||||
if db_id == 1:
|
||||
return tenant_id << 40 | db_id
|
||||
else:
|
||||
return db_id
|
||||
|
||||
def get_args(args):
|
||||
parser = argparse.ArgumentParser(add_help = False)
|
||||
parser.add_argument('-h', '--host', dest='host', type=str)
|
||||
parser.add_argument('-P', '--port', dest='port', type=int)
|
||||
parser.add_argument('-u', '--username', dest='username', type=str)
|
||||
parser.add_argument('-p', '--password', dest='password', type=str)
|
||||
parser.add_argument('-t', '--tenant', dest='tenant', type=int)
|
||||
parser.add_argument('-d', '--dump', dest='dump', action='store_true')
|
||||
parser.add_argument('-i', '--import', dest='import1', action='store_true')
|
||||
ret = parser.parse_args(args)
|
||||
|
||||
if ret.host == None:
|
||||
print >> sys.stderr, 'please give hostname: -h'
|
||||
return -1
|
||||
else:
|
||||
g_config.host = ret.host
|
||||
|
||||
if ret.port == None:
|
||||
print >> sys.stderr, 'please give port: -P'
|
||||
return -1
|
||||
else:
|
||||
g_config.port = ret.port
|
||||
|
||||
if ret.username == None:
|
||||
print >> sys.stderr, 'please give username: -u'
|
||||
return -1
|
||||
else:
|
||||
g_config.username = ret.username
|
||||
|
||||
if ret.tenant == None:
|
||||
print >> sys.stderr, 'please give tenant_id: -t'
|
||||
return -1
|
||||
else:
|
||||
g_config.tenant = ret.tenant
|
||||
|
||||
g_config.password = ret.password
|
||||
|
||||
if ret.dump == False and ret.import1 == False:
|
||||
print >> sys.stderr, 'please give dump or import: -d/-i'
|
||||
return -1
|
||||
elif ret.dump == True and ret.import1 == True:
|
||||
print >> sys.stderr, 'only dump or import: -d/-i'
|
||||
return -1
|
||||
else:
|
||||
g_config.dump = ret.dump
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def output(name, sql_id, outline_data):
|
||||
g_stat.outline_count += 1
|
||||
print "create outline auto_gen_%s on '%s' using hint %s;" % (name, sql_id, outline_data)
|
||||
|
||||
def check(lines):
|
||||
for i in range(1,len(lines)):
|
||||
if lines[i][1] != lines[0][1]:
|
||||
return False
|
||||
elif lines[i][2] != lines[0][2]:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_db_name(db_id):
|
||||
conn = get_connect()
|
||||
cur = conn.cursor()
|
||||
sql = "select database_name from oceanbase.__all_database where database_id = %d and tenant_id = %d" % (db_id, g_config.tenant)
|
||||
cur.execute(sql)
|
||||
rs = cur.fetchone()
|
||||
return rs[0]
|
||||
|
||||
|
||||
def dump_db_outline(db_id, items):
|
||||
if db_id == 18446744073709551615:
|
||||
for item in items:
|
||||
print >> sys.stderr, "sql_id = %s | sql_text = %s : no use database" % (item[0], item[1])
|
||||
return
|
||||
db_name = get_db_name(db_id)
|
||||
g_stat.db_count += 1
|
||||
print
|
||||
print "use %s;" % db_name
|
||||
map = {}
|
||||
for line in items:
|
||||
sql_id = line[0]
|
||||
sql_text = line[1]
|
||||
outline_data = line[2]
|
||||
|
||||
if sql_id in map:
|
||||
map[sql_id].append((sql_id, sql_text, outline_data))
|
||||
else:
|
||||
map[sql_id] = [(sql_id, sql_text, outline_data)]
|
||||
|
||||
count = 0
|
||||
for k, v in map.items():
|
||||
name = '%d_%s%d' % (g_config.tenant, db_name, count)
|
||||
if len(v) == 1:
|
||||
output(name, v[0][0], v[0][2])
|
||||
else:
|
||||
if check(v):
|
||||
output(name, v[0][0], v[0][2])
|
||||
else:
|
||||
print >> sys.stderr, "sql_id = %s has conflict" % (v[0][0])
|
||||
count += 1
|
||||
|
||||
|
||||
def dump_outline():
|
||||
conn = get_connect()
|
||||
cur = conn.cursor()
|
||||
cur.execute('select count(1) from oceanbase.__all_server')
|
||||
rs = cur.fetchone()
|
||||
server_count = rs[0]
|
||||
cur.execute('select db_id, sql_id, statement, outline_data from oceanbase.GV$OB_PLAN_CACHE_PLAN_STAT where tenant_id = %d order by db_id' % g_config.tenant)
|
||||
rs = cur.fetchall()
|
||||
last_db_id = 0
|
||||
items = []
|
||||
for i in range(0, len(rs)):
|
||||
db_id = get_real_db_id(1, rs[i][0])
|
||||
if db_id == last_db_id:
|
||||
items.append(rs[i][1:])
|
||||
else:
|
||||
if len(items) != 0:
|
||||
dump_db_outline(last_db_id, items)
|
||||
items = []
|
||||
last_db_id = db_id
|
||||
items.append(rs[i][1:])
|
||||
if len(items) != 0:
|
||||
dump_db_outline(last_db_id, items)
|
||||
items = []
|
||||
print >> sys.stderr, "%d database and %d outline dumped" % (g_stat.db_count, g_stat.outline_count)
|
||||
|
||||
#导入outline。判断outline是否存在。如果存在,那么就不导入了。
|
||||
#
|
||||
#查询__all_outline表。判断是否全部正确导入。
|
||||
#
|
||||
#输出导入信息。
|
||||
#1. 总共导入了多少outline, 之前已经存在多少outline
|
||||
#2. 中间有冲突的信息输出
|
||||
|
||||
def import_outline():
|
||||
conn = get_connect()
|
||||
cur = conn.cursor()
|
||||
cur.execute("select effective_tenant_id()")
|
||||
rs = cur.fetchone()
|
||||
if rs[0] != g_config.tenant:
|
||||
print >> sys.stderr, 'tenant id not equal %d <> %d' % (rs[0], g_config.tenant)
|
||||
sys.exit(-1)
|
||||
|
||||
state = 0
|
||||
for line in sys.stdin:
|
||||
line = line.strip()
|
||||
if len(line) != 0 and line[0] != '#':
|
||||
if len(line) >= 3 and line[:3] == 'use':
|
||||
print >> sys.stderr, 'change database: %s' % line
|
||||
try:
|
||||
cur.execute(line)
|
||||
state = 0
|
||||
g_import_stat.succ_db_count += 1
|
||||
except:
|
||||
g_import_stat.fail_db_count += 1
|
||||
print >> sys.stderr, 'fail to execute: %s' % line
|
||||
state = 1
|
||||
else:
|
||||
if state == 0:
|
||||
try:
|
||||
cur.execute(line)
|
||||
g_import_stat.succ_outline_count += 1
|
||||
except:
|
||||
print >> sys.stderr, 'fail to execute: %s' % line
|
||||
g_import_stat.fail_outline_count += 1
|
||||
else:
|
||||
g_import_stat.fail_outline_count += 1
|
||||
print >> sys.stderr, 'skip to execute: %s' % line
|
||||
print >> sys.stderr, "db succ %d | db fail %d | outline succ %d | outline fail %d" % (g_import_stat.succ_db_count, g_import_stat.fail_db_count, g_import_stat.succ_outline_count, g_import_stat.fail_outline_count)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if -1 == get_args(sys.argv[1:]):
|
||||
sys.exit(-1)
|
||||
|
||||
if g_config.dump:
|
||||
conn = get_connect()
|
||||
cur = conn.cursor()
|
||||
cur.execute("select effective_tenant_id()")
|
||||
rs = cur.fetchone()
|
||||
if rs[0] != 1:
|
||||
print >> sys.stderr, 'please use sys tenant to dump'
|
||||
sys.exit(-1)
|
||||
|
||||
cur.execute("select * from oceanbase.__all_tenant where tenant_id = %d" % g_config.tenant)
|
||||
rs = cur.fetchall()
|
||||
if 1 != len(rs):
|
||||
print >> sys.stderr, 'no such tenant_id %d ' % g_config.tenant
|
||||
sys.exit(-1)
|
||||
|
||||
dump_outline()
|
||||
else:
|
||||
import_outline()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user