Python中MySQL查询缓慢,但在其他地方很快

4
我在处理Python中缓慢的MySQL查询方面遇到了很大的困难。在我的应用程序的一个区域,“load data infile”速度很快。但在另一个区域,选择查询非常慢。在PhpMyAdmin和Navicat中执行相同的查询(作为第二个测试)比在Python中快约5倍。
一些注意事项: - 我切换到了MySQLdb作为连接器,并且还使用了SSCursor。没有性能提升。 - 数据库已经过优化、索引等。我正在将此应用程序从运行良好的PHP/Codeigniter迁移到Python,但我愚蠢地认为离开PHP会加速它。 - PHP/Codeigniter可以迅速执行选择查询。例如,应用程序的一个关键方面在PHP/Codeigniter中需要约2秒,但在Python中,在执行任何数据分析之前就需要10秒。
我的数据库链接相当标准...
dbconn=MySQLdb.connect(host="127.0.0.1",user="*",passwd="*",db="*", cursorclass = MySQLdb.cursors.SSCursor)

希望能得到任何见解/帮助/建议!

更新

就获取/处理结果而言,我尝试了几种方法。最初的查询方式相当标准...

# Run Query
cursor.execute(query)

我删除了这个循环中的所有代码,以确保它不是瓶颈,并且它确实不是。我放置了虚拟代码。整个过程并没有加快速度。

db_results = "test"

# Loop Results
for row in cursor:

    a = 0 (this was the dummy code I put in to test)

return db_results

查询结果本身只有501行(列数很多)......在Python之外只花了0.029秒。但在Python内部,需要更长时间。

这个项目与赛马有关。查询是在这个函数中完成的。查询本身很长,但在Python之外运行良好。我故意注释了循环内的代码进行测试......还有print(query),希望找出原因。

# Get PPs
def get_pps(race_ids):

# Comma Race List
race_list = ','.join(map(str, race_ids))

# PPs Query
query = ("SELECT raceindex.race_id, entries.entry_id, entries.prognum, runlines.line_id, runlines.track_code, runlines.race_date, runlines.race_number, runlines.horse_name, runlines.line_date, runlines.line_track, runlines.line_race, runlines.surface, runlines.distance, runlines.starters, runlines.race_grade, runlines.post_position, runlines.c1pos, runlines.c1posn, runlines.c1len, runlines.c2pos, runlines.c2posn, runlines.c2len, runlines.c3pos, runlines.c3posn, runlines.c3len, runlines.c4pos, runlines.c4posn, runlines.c4len, runlines.c5pos, runlines.c5posn, runlines.c5len, runlines.finpos, runlines.finposn, runlines.finlen, runlines.dq, runlines.dh, runlines.dqplace, runlines.beyer, runlines.weight, runlines.comment, runlines.long_comment, runlines.odds, runlines.odds_position, runlines.entries, runlines.track_variant, runlines.speed_rating, runlines.sealed_track, runlines.frac1, runlines.frac2, runlines.frac3, runlines.frac4, runlines.frac5, runlines.frac6, runlines.final_time, charts.raceshape "
         "FROM hrdb_raceindex raceindex "
         "INNER JOIN hrdb_runlines runlines ON runlines.race_date = raceindex.race_date AND runlines.track_code = raceindex.track_code AND runlines.race_number = raceindex.race_number "
         "INNER JOIN hrdb_entries entries ON entries.race_date=runlines.race_date AND entries.track_code=runlines.track_code AND  entries.race_number=runlines.race_number AND entries.horse_name=runlines.horse_name "
         "LEFT JOIN hrdb_charts charts ON runlines.line_date = charts.race_date AND runlines.line_track = charts.track_code AND runlines.line_race = charts.race_number "
         "WHERE raceindex.race_id IN (" + race_list  + ") "
         "ORDER BY runlines.line_date DESC;")

print(query)

# Run Query
cursor.execute(query)

# Query Fields
fields = [i[0] for i in cursor.description]

# PPs List
pps = []

# Loop Results
for row in cursor:

    a = 0
    #this_pp = {}

    #for i, value in enumerate(row):
    #    this_pp[fields[i]] = value            

    #pps.append(this_pp)

return pps

最后说明一点...我还没有考虑处理结果的理想方式。我认为一个游标可以将结果返回为一组字典。由于查询和返回本身非常缓慢,我甚至还没有达到那个阶段。


1
通常这不是SQL的问题,而是与您获取和处理结果的方式有关。几行代码可以帮助Python开发人员追踪此问题。 - cypherabe
可以切换回正常的光标并重新检查查询执行速度吗? - alecxe
我一开始以为是普通光标的原因。但两者都产生了类似缓慢的结果。 - TravisVOX
MySQL为Python提供了两个提供程序。尝试另一个。 - Michael Kazarian
cdent -- 我添加了查询数据库和结果的函数。请注意,即使这个设置(没有对结果集进行大量“工作”)也需要太长时间。 - TravisVOX
显示剩余4条评论
2个回答

2

尽管您只有501行,但看起来似乎有超过50列。从MySQL传递到Python的总数据量是多少?

501行 x 55列 = 返回27,555个单元格。

如果每个单元格平均"仅"为1K,那么返回近27MB的数据量。

为了了解MySQL正在推送的数据量,可以将此添加到您的查询中:

SHOW SESSION STATUS LIKE "bytes_sent"

您的服务器是否配置良好?内存分配是否已经配置好?

我猜想,当您使用PHPMyAdmin时,您会得到分页结果。这掩盖了MySQL返回比您的服务器处理能力更多数据的问题(我不使用Navicat,不确定其返回结果的方式)。

也许Python进程受到内存限制,当面临这么大的结果集时,它必须将页面输出到磁盘以处理结果集。

如果您减少所调用的列数和/或限制查询,例如LIMIT 10,是否可以提高速度?

您能否查看运行Python的服务器在调用此查询时是否正在进行磁盘页面交换?您能否查看为Python分配了多少内存,在该过程中使用了多少内存,以及与PHP版本中相同值的分配和使用情况如何比较?

您能否为受限资源分配更多内存?

您能否通过分页或异步加载来减少所调用的列数或行数?


感谢您的反馈。就设置方面而言,我们使用了全新的机器,拥有64G内存、重量级处理器等等。我会尝试减少结果数量,但不管怎样,运行速度缓慢感觉就像是一场灾难。我会再次汇报。谢谢! - TravisVOX
MySQL和Python是否在同一台服务器上? - AllInOne
MySQL和PHP在同一台服务器上吗? - AllInOne
是的,它们都在同一台机器上。这台机器非常强大...有64G内存等等。 - TravisVOX
我的回答中提出的问题有任何新的报告吗? - AllInOne
嘿——我已经尝试了各种选项、组合、调整等。说实话,没有什么比将CSV文件读入Pandas更快了。查询数据库、获取数据等,都无法与读取平面文件的速度相媲美。 - TravisVOX

1

我知道现在有点晚了,但是我遇到了与mysql和python相关的类似问题。我的解决方案是使用另一种语言进行查询......我使用R来进行查询,它非常快速,如果需要进行更一般的编程,可以将数据发送到python,虽然R也有许多通用库。只是想发布一些可能会帮助到有类似问题的人的东西,我知道这绕过了问题的核心。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接