前面讲过 连接数据库【一】,主要是去表里Select;这次说下Insert;
在我印象中,使用pymysql库 在表里插入、修改、删掉数据,好像都是要 先commit下,才能将数据写入;
这儿说个 小技巧,是Connection类的autocommit :
先看下 Connection的注释
:param autocommit: Autocommit mode. None means use server default. (default: False)
默认是Fasle; 我现在都是设置为True:
db = pymysql.connect('x.x.x.x', 'zyooooxie', 'csdn', 'db', autocommit=True)
唯一的好处是 自动提交,不必每次执行sql后 要Commit() ;
说些实际应用:某供应商系统,要检验 某供应商 日结明细某些字段值 和 当天订单的相关字段值的关系(类似 某天全部订单交易手续费 和每笔交易的手续费的关系);那就要往库表插入很多数据了;
先看下 字段【有省略】:
思路:
def insert_data(self, vendor_info, start_date=None, end_date=None):
if start_date is None:
st = '20200102'
else:
st = start_date
if end_date is None:
en = (datetime.date.today() - datetime.timedelta(days=1)).strftime('%Y%m%d')
else:
en = end_date
dt_list = self.date_list(st, en) # 某时间段
db = pymysql.connect('xie.xie.xie.xie', 'zyooooxie', 'csdn', 'xie', autocommit=True)
cur = db.cursor()
for vendor in vendor_info:
vendor_id = vendor[0]
vendor_name = vendor[1]
for dt in dt_list:
receive_time = int(round(1000 * (time.mktime(time.strptime(dt + ' 12:20:30', "%Y%m%d %H:%M:%S")))))
data_list = random.sample(range(100000, 999999), 3) # 随机取3个不重复的值
for i in data_list:
# 订单id为 date + 某价格 【1. date不同 2. date相同,但价格不同;故不会出现相同订单id】
order_id = ''.join([dt, str(i)])
settlement_price = i
supply_price = settlement_price + 50
fee = 50 # 写死
sql = "INSERT INTO t_order (vendor_id, vendor_name, order_id, settlement_price, supply_price, fee, order_status, receive_time) VALUES ({}, '{}', {}, {}, {}, {}, 'zyooooxie', {});".format(vendor_id, vendor_name, order_id, settlement_price, supply_price, fee, receive_time)
cur.execute(sql)
time.sleep(0.01)
cur.close()
db.close()
此外,既然有签收订单,肯定有退款的单子咯,这儿说下 退款时间refund_time
refund_time bigint null comment '订单退款时间(Refund Time)',
假设:除了 最后一天 退款时间为当天(订单时间只到昨天, 昨天的退款单子都是 当天退的),其他时间里的订单都是 后面一天退的;
if dt_list[-1] != dt:
new_dt_index = dt_list.index(dt) + 1
refund_dt = dt_list[new_dt_index]
else:
refund_dt = dt
refund_time = int(
round(1000 * (time.mktime(time.strptime(refund_dt + ' 17:16:15', "%Y%m%d %H:%M:%S")))))
这脚本用起来,确实节省太多人工;省了我很多力气;
(上面讲的是 插入order订单,另外 插入recharge充值明细 + 插入daily report日结明细 都雷同;
各种数据生成后,需要fix,实际修复数据脚本的思路 也类似)
在实际工作中,有时候可能会出现很大数据量,可能平均每天的订单数量就超过十万条,那怎么样插入数据 更快呢?
上面情景中,按我的代码,大概每秒钟 插入30-50条记录;如何实现每秒插入数万条数据呢?
executemany()就是为此情景带来希望,可实现 多行插入;
这儿只说一点经验:
每个字段的字段值 都写入 all_data 【VALUES() 里面都是 %s,不能出现 某字段值】;
all_data = list()
all_data.append((vendor_id_name[0], vendor_id_name[1], 'IDR', order_id, settlement_price, supply_price, fee, 91, create_time, refund_time))
sql_1 = "INSERT INTO `t_order` (vendor_id, vendor_name, currency, order_id, settlement_price, supply_price, fee, status, receive_time, refund_time) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s);"
cur.executemany(sql_1, all_data)
凭啥不能写成如下?
all_data = list()
all_data.append((vendor_id_name[0], vendor_id_name[1], order_id, settlement_price, supply_price, fee, create_time, refund_time))
sql_1 = "INSERT INTO `t_order` (vendor_id, vendor_name, currency, order_id, settlement_price, supply_price, fee, status, receive_time, refund_time) VALUES (%s, %s, 'IDR', %s, %s, %s, %s, 91, %s, %s);"
cur.executemany(sql_1, all_data)
因为后面一种速度慢 = _ = 【我也不知道原因啦,没有深入的学习】
这儿说的是:一条sql语句插入多条数据;Insert into 表名 (某字段名a,某字段名b) Values (a1, b1), (a2, b2), (a3, a4);
正常连库,插入数据,其实本不用这样做,但某些情景下,只能用sql语句来做的时候,我觉着这样做 相对一条一条insert语句去执行,会高效些;
【最近有个联调环境,只能通过堡垒机去登录后,再去访问数据库;运维同事不给开放连接数据库的权限,我又偏偏要造大数据量,咋整呢?】
def test_0427(self, date_list, table, ssh_channel):
"""某时间段,每天插入40w,每条sql插入200条记录"""
for d in date_list:
Log.info('时间为 {}'.format(d))
kaishi = 1
jie = 400000
abc_list = range(kaishi, jie)
for st in range(0, math.ceil(len(abc_list) / 10000)):
Log.info('第{}个1w条数据'.format(st))
kai = kaishi + st * 10000
for abc in range(math.ceil(10000 / 200)):
Log.info('页数 {}'.format(abc))
start = kai + abc * 200
end = 200 + start
day_data = list()
# Log.info(start)
# Log.info(end)
for a in range(start, end):
gateway_order_id = int(''.join([d, "{:0>6d}".format(a)]))
gateway_amount = random.choice([a, a, a, a * 35])
gateway_transaction_status = random.choice([1, 9, 2, 3, 4, 5, 6])
transaction_order_date_timestamp = int(d)
day_data.append((gateway_order_id, gateway_amount, gateway_transaction_status,
transaction_order_date_timestamp))
sql = "insert into {} (gateway_order_id, gateway_amount,gateway_transaction_status,transaction_order_date_timestamp) VALUES {};".format(
table, tuple(day_data)).replace('((', '(').replace('))', ')')
ssh_channel.send(sql)
ssh_channel.send('\r')
这样做,insert 的速度 比起前一种差太多;而且sql语句是有SQL长度限制;还是推荐前面那一种来做。
交流技术 欢迎+QQ 153132336 zy
个人博客 https://blog.csdn.net/zyooooxie