1.准备 INSERT 的字典,其实有三个字段(物品名称
,型号
,序号
)内容,与表中已有的条目三个相同,这个准备插入的字典已经可以被认为是重复的,不需 INSERT,
字典全部字段有 32 个.
2.for 循环字典列表,逐条判断写入,字典列表有 900 个字典的话,需时 79 秒,虽然是练手学习,也无法接受
3.用
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(50) as executor:
for each in testDictList:
executor.submit(thDictSQL, SQLServerInfo,'testTBL',each,checkField)
仅需 48 秒能写入.
改成 ThreadPoolExecutor(500),39 秒,但是很大几率会丢了一些条目
# dict 转换成 SQL 语句
def DicttoSQLText(obj, tblName, SQLcmd):
returnText = ''
FiledStr = ''
ValueStr = ''
ccount = 0
if isinstance(obj, list):
for i in obj:
FiledStr = ', '.join(list(i.keys()))
ValueStr = "'" + '\', \''.join(list([str(x) for x in i.values()])) + "'"
SQLText = SQLcmd.format(tblName, FiledStr, ValueStr)
returnText += SQLText
ccount += 1
return returnText
if isinstance(obj, dict):
FiledStr = ', '.join(list(obj.keys()))
ValueStr = "'" + '\', \''.join(list([str(x) for x in obj.values()])) + "'"
SQLText = SQLcmd.format(tblName, FiledStr, ValueStr)
returnText += SQLText
ccount += 1
return returnText
# 执行 SQL 语句,返回字典结果
def SQLcmdData(cur, sqlcmd):
cur.execute(sqlcmd)
data = cur.fetchall()
if len(data) == 1:
return data[0]
else:
return data
# Insert 字典数据(函数可以用在 thread)
def thDictSQL(SerInfo, tblName, dataDict, checkField):
thSQLconn = pymysql.connect(host=SQLServerInfo['ip'], port=SQLServerInfo['port'], user=SQLServerInfo['user'],
password=SQLServerInfo['password'], database=SQLServerInfo['database'],
charset=SQLServerInfo['charset'])
thSQLCursor = thSQLconn.cursor(cursor=pymysql.cursors.DictCursor)
# 检查有无相同项目
checkStr = ''
# 组装检查 SQL 语句
for i in checkField:
checkStr += f"`{i}`='{dataDict.get(i)}' AND "
checkStr = checkStr.rstrip(checkStr[-4:])
thSQLSelectText = "SELECT id FROM {} WHERE ({})".format(tblName, checkStr)
ret = thSQLCursor.execute(thSQLSelectText)
# 根据检查结果写入
if not thSQLCursor.fetchall():
thSQLInsertText = DicttoSQLText(dataDict, "INSERT INTO {} ({}) VALUE ({});")
ret = SQLcmdData(thSQLCursor, thSQLInsertText)
thSQLCursor.close()
thSQLconn.close()
return thResult
if __name__ == '__main__':
testDictList = None
with open('h:/dd.dict', 'r') as f:
testDictList = eval(f.read())
StartTime = time.clock()
checkField = ['物品名称', '型号', '序号']
for i in testDictList:
i['DL'] = 0
i['DB'] = 0
i['UpdateTime'] = myFunc.nowTimeForStr()
thDictSQL(SQLServerInfo, 'cangku', i, checkField)
print(time.clock() - StartTime)
1
dorothyREN 2020-08-29 23:40:37 +08:00
三个字段设置唯一,然后直接插入,有重复的数据插入会返回异常,然后忽略异常。。。。。
|
2
chihiro2014 2020-08-29 23:44:03 +08:00
先查再插
|
3
zhangjiale 2020-08-29 23:47:28 +08:00
```sql
insert ignore ``` |
4
qile1 2020-08-30 00:19:43 +08:00 via Android
用 sql 语句 if not exect
|
5
johnsona 2020-08-30 02:22:20 +08:00
一次性提交
|
6
singerll 2020-08-30 03:40:09 +08:00 via Android
单条 insert,神仙也救不了。
用不重复的字典读,一条 insert 提交 |
7
widewing 2020-08-30 03:56:05 +08:00 via Android
Upsert 或 merge into 吧这种 case
|
8
msg7086 2020-08-30 10:06:20 +08:00
拿到 900 条数据,从数据库里用这 900 条记录搜索,返回现有的记录。
删掉重复的记录,然后一次性插入。 估摸着两三秒撑死了。 当然,这是不考虑 race condition 的情况。 |
9
chaogg 2020-08-30 11:19:48 +08:00
才 900 条,物品名称,型号,序号建联合索引,逐条插入,如果用 ORM,每次插入前先查询一下是否存在。如果用 sql 语句,则可以用 if not exect
|
10
xiaolinjia 2020-08-30 14:13:25 +08:00
2020 了,还用 pymysql 。不知道 pymysql 是纯 py 实现的,c 实现的 mysqlclient 会快不少吗。
|
11
Tompes 2020-08-30 14:33:52 +08:00 via Android
整个布隆过滤器
|
12
guanhui07 2020-08-30 14:54:52 +08:00 via iPhone
if not exect
|
13
chenqh 2020-08-30 16:12:58 +08:00
@xiaolinjia 虽然不想说,但是我跑我的测试的时候 mysqlclient 并没有比我用 pymysql 快
|
14
chenqh 2020-08-30 16:14:11 +08:00
如果数据库的数量不大的,直接把数据库的记录读到本地,建立一个 set, 这样可能会快点
|
15
13936 2020-08-31 09:35:35 +08:00
on duplicate 呗。这也不知道?
|
16
TEwrc 2020-09-01 16:37:50 +08:00
应该有参数控制的,我在写`mongodb`也遇到这种问题,我是这么解决的:
`client[db_name][collection_name].update_one({"name":info['name']},{'$setOnInsert':{"value":info["value"]}},True)` |