理解MySQL游标类型

15 投票
1 回答
1436 浏览
提问于 2025-04-18 13:39

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 个回答

9

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 论坛 上讨论。

撰写回答