理解MySQL游标类型
MySQL版本:5.5.37-0ubuntu0.14.04.1
我现在正在写一个Python脚本,这个脚本使用了很多MySQL表和查询,从存储在表中的倒排索引中获取结果。
我发现,在使用MySQLdb这个Python模块执行查询时,选择合适的游标类型对性能影响非常大。我想知道有没有人能解释一下,或者提供一个可靠的资源,告诉我什么时候该用哪个游标。
举个例子,使用SSCursor执行这个查询40次需要7秒:
SELECT Pages.PageID,
Pages.PageName,
Counter AS TermFreq,
Pages.Length,
(Counter / LOG(Length)) AS Weight
FROM Pages
INNER JOIN TermOccurrences ON TermOccurrences.PageID = Pages.PageID
INNER JOIN Terms ON TermOccurrences.TermID = Terms.TermID
WHERE TermName = %s
ORDER BY Weight DESC
LIMIT 20;
而使用默认游标执行同样的查询40次只需要0.004秒。
如果去掉权重计算(Counter/LOG(Length)),使用SSCursor执行这个查询又会变得很快。
我之前使用SSCursor是因为它在很多其他查询中表现得非常好,但突然在这个查询上变得很慢。切换回默认游标让我很惊讶,因为它执行得这么快。
编辑:再举几个例子。
使用默认游标执行以下查询40次大约需要3秒:
SELECT COUNT(*)
FROM Pages
INNER JOIN TermOccurrences ON TermOccurrences.PageID = Pages.PageID
INNER JOIN Terms ON TermOccurrences.TermID = Terms.TermID
WHERE TermName = %s AND Counter > 2
而使用SSCursor执行则只需要大约0.002秒。
1 个回答
MySQLdb 的文档提到,标准的 Cursor 类使用的是 mysql_store_result()
,而 SSCursor 则使用 mysql_use_result()
。“使用后者时,必须确保在执行另一个查询之前,所有的行都已经被读取。”
所以这里主要是 mysql_store_result()
和 mysql_use_result()
的区别。
MySQL 的文档提到,mysql_use_result()
启动结果集的获取,但并不会像 mysql_store_result()
那样把结果集全部读入客户端。因此,每一行都需要通过调用 mysql_fetch_row()
单独获取,这在处理大表时会变得非常耗时。
在 MySQLdb 的文档中还有提到:
SSCursor:一种“服务器端”的游标。和 Cursor 类似,但使用 CursorUseResultMixIn。只有在处理可能很大的结果集时才使用。
所以 SSCursor
主要适合当你的结果集太大,无法一次性全部传送到客户端时使用。
还可以参考这些问题:
另外要注意,LIMIT 20
的查询结果其实不可能真的很大。你可能需要检查一下你的键。想要更好地理解为什么可能需要 7 秒,最好在提问时也附上数据库的结构,这可能更适合在 DBA 论坛 上讨论。