python - 大量更新的脚本优化

标签 python mysql optimization sql-update

我正在编写一个脚本,该脚本创建一些数据的哈希值并将其保存在数据库中。所需的数据来自 SQL 查询,该查询将大约 300k 行与 500k 行连接起来。在解析结果时,我创建哈希值并使用第二个连接处理程序在数据库中更新(使用第一个连接处理程序会给我一个“未读结果”错误)。

经过大量调查后,我发现在性能方面给我带来最佳结果的因素如下:

  • 每 x 次迭代重新启动选择查询。否则,在一段时间后更新会变慢
  • 仅每 200 个查询提交一次,而不是对每个查询都提交
  • 用于选择查询的表是 MyISAM,并使用主键和联接中使用的字段进行索引。
  • 我的哈希表是 InnoDB,只有主键 (id) 被索引。

这是我的脚本:

commit = ''       
stillgoing = True    
limit1 = 0
limit2 = 50000    
i = 0    
while stillgoing:    
    j = 0    
    # rerun select query every 50000 results
    getProductsQuery = ("SELECT distinct(p.id), p.desc, p.macode, p.manuf, "
        "u.unit, p.weight, p.number, att1.attr as attribute1, p.vcode, att2.attr as attribute2 "
        "FROM p "
        "LEFT JOIN att1 on p.id = att1.attid and att1.attrkey = 'PARAM' "
        "LEFT JOIN att2 on p.id = att2.attid and att2.attrkey = 'NODE' "
        "LEFT JOIN u on p.id = u.umid and u.lang = 'EN' "
        "limit "+str(limit1)+", "+str(limit2))                           
    db.query(getProductsQuery)
    row = db.fetchone()              
    while row is not None:
        i += 1
        j += 1
        id = str(row[0])
        # create hash value
        to_hash = '.'.join( [ helper.tostr(s) for s in row[1:]] )
        hash = hashlib.md5(to_hash.encode('utf-8')).hexdigest()
        # set query
        updQuery = ("update hashtable set hash='"+hash+"' where id="+id+" limit 1" )         
        # commit every 200 queries
        commit = 'no'
        if (i%200==0):
            i = 0
            commit = 'yes'
        # db2 is a second instance of db connexion
        # home made db connexion class
        # query function takes two parameters: query, boolean for commit
        db2.query(updQuery,commit)            
        row = db.fetchone()        
    if commit == 'no':
        db2.cnx.commit()            
    if j < limit2:
        stillgoing = False
    else:
        limit1 += limit2

目前,该脚本需要 1 小时 30 到 2 小时才能完全运行。这些是自剧本第一个版本以来我得到的更好的表演。我可以做些什么来让它运行得更快吗?

最佳答案

... LIMIT 0,200  -- touches 200 rows
... LIMIT 200,200  -- touches 400 rows
... LIMIT 400,200  -- touches 600 rows
... LIMIT 600,200  -- touches 800 rows
...

有照片吗? LIMIT + OFFSET 是 O(N*N)。速度慢得多。

要将其降低到 O(N),您需要执行一次线性扫描。如果单个查询(没有 LIMIT/OFFSET)花费太长时间,则遍历“ block ”中的表:

... WHERE id BETWEEN 1 AND 200  -- 200 rows
... WHERE id BETWEEN 201 AND 400  -- 200 rows
... WHERE id BETWEEN 401 AND 600  -- 200 rows
... WHERE id BETWEEN 601 AND 800  -- 200 rows

我在博客上写了这样的here 。如果您要更新的表是 InnoDB 并且具有 PRIMARY KEY(id),则按 id 分块非常高效。

您可以设置 autocommit=1,以便每个 200 行 UPDATE 自动COMMITs

哦,你的表用的是古董引擎MyISAM?嗯,它会运行得相当好。

关于python - 大量更新的脚本优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32248703/

相关文章:

php - 如何使用 PATCH 更新一个简单的数据库字段?

c++ - 如何批量分配 boost::ptr_vector 并调用存储类的构造函数?

java - 黑白棋走法计算优化 (Bitboard)

python - Spark 读取二进制文件的子组

python - 在 Python 的控制台中显示表情符号

python - 如何使用周期性值列拆分 pandas 数据框

python - 使用 Beautiful Soup 解析时的“无”属性

mysql - SQL 字符串的正则表达式只允许对变量命名表进行 SELECT 查询?

c# - Elmah MySql Nuget 包问题 'Could not load file or assembly'

c++ - 优化 C++ 中的模块化算术计算