面试问题:如何创建10w测试数据并将10w不同的数据插入数据库?
面试问题:如果创建10w测试数据,如何将10w数据无重复地插入数据库?
最近面试经常问sql相关的问题。在数据库中创建测试数据是日常工作中常见的场景。一般压力测试和性能测试也需要先在数据库中准备好测试数据。那么如何批量生成大量的测试数据呢?
因为经常使用python,所以想到了用python生成sql,然后执行sql将数据插入数据库。
语言:python 3.6
插入数据
首先我要插入SQL语句,每个id不要重复。下面是一条insert语句的执行过程。
插入到apps.apiapp_card (id,card_id,card_user,add_time)值(' 1 ','',' test123 ',' 2019-12-17 ');
10w执行时间太长。用python先生用1w测执行时间。
首先,我需要生成多个惰性语句。这里我用python语言写段落生成sql文本。
将需要更改的字段值替换为% s,如果需要更改多个值,可以将对应的值替换为多个% s,我这里设计的表,只要id不同就可以成功插入。
使用for循环,在每个循环的id上加1,这样可以保证id不重复,否则插入数据库时重复的ID无法写入成功。
a是附加文字。
用分号分隔每个sql。
每次写数据的时候,在末尾加一个换行符。
python3
作者:上海优优QQ群717225969
对于范围内的I(10000):
a = " INSERT INTO apps . API app _ card(id,card_id,card_user,add_time)值(' %s ','',' test123 ',' 2019-12-17 ');"%str(i+1)
用open("a.txt "," a ")作为fp:
fp.write(a+"\n ")
执行python代码,在本地生成a.text文件,打开生成的数据。该部分如下。
插入到apps.apiapp_card (id,card_id,card_user,add_time)值(' 1 ','',' test123 ',' 2019-12-17 ');
插入到apps.apiapp_card (id,card_id,card_user,add_time)值(' 2 ','',' test123 ',' 2019-12-17 ');
插入到apps.apiapp_card (id,card_id,card_user,add_time)值(' 3 ','',' test123 ',' 2019-12-17 ');
插入到apps.apiapp_card (id,card_id,card_user,add_time)值(' 4 ','',' test123 ',' 2019-12-17 ');
......
插入到apps.apiapp_card (id,card_id,card_user,add_time)值(' 10000 ','',' test123 ',' 2019-12-17 ');
如果id是手机号,如何生成10w个不同的手机号?
可以根据手机号码前三位开头的号码字段生成,比如186开头的号码。首先初始数据是1860000000,然后数字每次加1。
加到1860009999,那么数字字段186000000-1860009999就是10w。
将id更改为手机号码后,按如下方式修改代码
python3
作者:上海优优QQ群717225969
对于范围内的I(10000):
a = " INSERT INTO apps . API app _ card(id,card_id,card_user,add_time)值(' %s ','',' test123 ',' 2019-12-17 ');"%str(i+1860000000)
用open("a.txt "," a ")作为fp:
fp.write(a+"\n ")
只要在上面的基础上把str(i+1)改成STR (I+186000000),就可以生成手机号了。
插入到apps.apiapp_card (id,card_id,card_user,add_time)值(' 1860000000 ','',' test123 ',' 2019-12-17 ');
插入到apps.apiapp_card (id,card_id,card_user,add_time)值(' 1860000001 ','',' test123 ',' 2019-12-17 ');
插入到apps.apiapp_card (id,card_id,card_user,add_time)值(' 1860000002 ','',' test123 ',' 2019-12-17 ');
复制生成的文本,将INSERT INTO对应的多个sql一次粘贴到navicat客户端执行。
执行完大概用了5分钟,也就是说10w要50分钟,太慢了。如果数据再多,时间就太长了,这不是我们想要的!
批量执行
因为单次执行时间太长,现在需要优化,改成惰性语句,批量插入数据,一次只写一个insert into来批量写入数据库,会快很多。
您可以拼接SQL语句,使用insert into table () values()、()、()、()、()然后一次插入它们。
要么所有批处理执行都成功,要么都不会成功写入。当写出来的SQL语法有问题,就写不成功。
注意:
拼接sql,用英文逗号分隔多个值。
该值应该与数据表中的字段一一对应。
一定要注意,最后一个数据后面不是逗号,而是分号。
python3
作者:上海优优QQ群717225969
insert_sql = "插入到apps.apiapp_card值"
用open("b.txt "," a ")作为fp:
fp.write(insert_sql+"\n ")
对于范围内的I(10000):
a = "('%s ','',' test123 ',' 2019-12-17 ')," %str(i+10001)
用open("b.txt "," a ")作为fp:
fp.write(a+"\n ")
执行完成后,复制b.text文件的内容。需要注意的是,这必须改为;结尾,否则语法是错误的。
一些数据内容如下所示。
插入到apps.apiapp_card值中
(' 10001 ','',' test123 ',' 2019-12-17 '),
(' 10002 ','',' test123 ',' 2019-12-17 '),
......
(' 20000 ','',' test123 ',' 2019-12-17 ');
将生成的插入内容复制到navicat客户端以供执行。
执行后最终测试结果显示,1w条数据仅用时0.217秒,速度明显提升。
10w数据插入
那么,生成10 w条数据需要多长时间?
作者:上海优优QQ群717225969
python3
insert_sql = "插入到apps.apiapp_card值"
用open("b.txt "," a ")作为fp:
fp.write(insert_sql+"\n ")
对于范围内的I(100000):
a = "('%s ','',' test123 ',' 2019-12-17 ')," %str(i+100000)
用open("b.txt "," a ")作为fp:
fp.write(a+"\n ")
使用python脚本执行后生成的数据如下
插入到apps.apiapp_card值中
(' 100000 ','',' test123 ',' 2019-12-17 '),
(' 100001 ','',' test123 ',' 2019-12-17 '),
......
(' 199999 ','',' test123 ',' 2019-12-17 ');
如果直接插入mysql,会得到一个错误:err 1153-得到一个大于' max _ allowed _ packet '字节的数据包。
错误原因:mysql由于数据量大,会限制单表数据量大的sql,10w数据的字符串超过max_allowed_packet。
的允许范围。
解决方法:mysql数据库中max_allowed_packet的值需要修改的大一些。
最大允许数据包
首先,在navicat中输入命令,查看max_allowed_packet最大允许数据包。
显示全局变量,如“max _ allowed _ packet”;
发现值是4194304,最大限制是40 m,我们只需要的sql字符串太大,超出了这个范围。
在navicat客户端,我们不能直接修改对应的值,需要登录mysql,用命令行修改。
我的mysql是建立在docker上的,所以我需要一个高级的容器,登录mysql。
操作步骤如下:
Docker exec进入Docker容器。
Mysql-urot-p输入密码,登录Mysql。
set global max _ allowed _ packet = 419430400;设置最大允许数据包400M m
显示全局变量,如“max _ allowed _ packet”;检查之前的设置是否生效。
[root @ VM _ 0 _ 2 _ centos ~]# docker exec-it 934 b 30 a6 DC 36/bin/bash
root @ 934 b 30 a6 DC 36:/# MySQL-u root-p
输入密码:
欢迎使用MySQL monitor。命令以结尾;或者\g。
您的MySQL连接id是303822
服务器版本:5.7.27 MySQL社区服务器(GPL)
版权所有(c) 2000,2019,Oracle和/或其附属公司。版权所有
Oracle是Oracle Corporation和/或其
附属公司。其他名称可能是其各自的商标
业主。
键入“help”或“\h”寻求帮助。键入' \c '清除当前的输入语句。
mysql & gt显示全局变量,如“max _ allowed _ packet”;
+ - + - +
|变量名称|值|
+ - + - +
| max _ allowed _ packet | 4194304 |
+ - + - +
65438+集合中的0行(0.00秒)
mysql & gtset global max _ allowed _ packet = 419430400;
查询正常,0行受影响(0.00秒)
mysql & gt显示全局变量,如“max _ allowed _ packet”;
+ - + - +
|变量名称|值|
+ - + - +
| max _ allowed _ packet | 419430400 |
+ - + - +
65438+集合中的0行(0.00秒)
mysql & gt
从上面的查询结果可以看出,已经生效。
再次重新执行上述10w数据,检查运行结果大约需要11秒。
受影响的线路:100000
时间:11.678秒
以上方法只能暂时生效。当mysql重启后,你会发现已经恢复了。
还有一个永久的方法,需要修改my.cnf配置文件。
在[mysqld]部分添加一个句子,如果有,修改相应的值:
最大允许数据包=40M
这里的值可以以m为单位。修改后需要重启mysql才能生效。
在python中执行
如果用python代替navicat客户端需要多长时间?
先封装连接mysql的方法,然后拼接执行的sql语句。拼接时注意最后一个字符需要改成;
执行代码前获取当前时间戳,代码执行后再次获取时间戳。两次之间的时间间隔就是执行的时间,时间单位是s。
Python参考以下内容执行mysql代码
导入pymysql
'''
python3
作者:上海优优QQ群717225969
pip安装PyMySQL==0.9.3
'''
dbinfo = {
“主机”:“192.168.1.x”,
“用户”:“root”,
“密码”:“123456”,
【端口】:3306}
类DbConnect():
def init(self,db_cof,database= " "):
self.db_cof = db_cof
#打开数据库连接
self . db = pymysql . connect(database = database,
cursor class = pymysql . cursors . dict cursor,
**db_cof)
#使用cursor()方法获取操作光标。
self.cursor = self.db.cursor()
定义选择(自身,sql):
# SQL查询语句
# SQL = " SELECT * FROM EMPLOYEE # WHERE INCOME & gt;%s" % (1000)
self.cursor.execute(sql)
results = self.cursor.fetchall()
返回结果
定义执行(self,sql):
# SQL删除、提交和修改语句
# sql = "从员工中删除年龄& gt%s" % (20)
尝试:
#执行SQL语句
self.cursor.execute(sql)
#提交更改
self.db.commit()
除了:
#发生错误时回滚
self.db.rollback()
定义关闭(自己):
#关闭连接
self.db.close()
if name == 'main ':
导入时间
insert_sql = "插入到apps.apiapp_card值"
insert_values = " "。join(["('%s ','',' test123 ',' 2019-12-17 '),\ n " % str(I+100000)for I in range(10000)])
#拼接sql
sql =插入sql +插入值[:-3]+";"
#打印(sql)
#执行sql
time1 = time.time()
db = DbConnect(dbinfo,database="apps ")
数据库执行(sql)
db.close()
time2 = time.time()
Print("总运行时间:%s"% (time2-time1))
用python执行结果:总时间太长:1.016256999969482,结果超出我的想象。10w条数据只需要1秒!
面试问题:如何创建10w测试数据并将10w不同的数据插入数据库?
标签:sql语句改善名称data = ==commandatiblewhere