MySQL 游标占用大量内存

标签 mysql cursor

我对 MySQL 相当陌生,并且已将运行良好的 MSSQL 查询转换为 MySQL,但我发现 MySQL 版本最终在我的 Mac 上耗尽内存并停止。显然,我的转换工作存在缺陷。 :(

我需要查看一个有 88,000 行的表 (CurrentPages),尝试确定其 ContentBody 列(LongText 类型)是否包含第二个有 300 行的表(插件)中的一系列值中的任何一个。插件表中的“掩码”列包含类似“%{macro%”的内容。

我使用存储过程来迭代这两个表,存储在名为“Usage”的第三个表中找到的所有“命中”。

Create TABLE IF NOT EXISTS CurrentPages (
   ContentID      BIGINT(20)   NOT NULL PRIMARY KEY,
   SpaceKey       VARCHAR(255) NULL,
   PageTitle      VARCHAR(255) NULL,
   ViewURL        VARCHAR(255) NULL,
   OriginalAuthor VARCHAR(255) NULL,
   LastChangedBy  VARCHAR(255) NULL,
   LastChangedDt  VARCHAR(10)  NULL,
   ContentBody    LONGTEXT NULL
);

Create TABLE IF NOT EXISTS Plugins (
    MacroType       INT(10)         NOT NULL PRIMARY KEY,
    PluginName      VARCHAR(255)    NOT NULL,
    MacroName       VARCHAR(255)    NOT NULL,
    Mask            VARCHAR(255)    NOT NULL,
    Disposition     VARCHAR(255)    NOT NULL
);

Create TABLE IF NOT EXISTS Usage (
    ID              INT(10)         NOT NULL AUTO_INCREMENT PRIMARY KEY,
    MacroType       INT(10)         NOT NULL,
    SpaceKey        VARCHAR(255)    NOT NULL,
    PageTitle       VARCHAR(255)    NOT NULL,
    ViewURL         VARCHAR(255)    NOT NULL,
    PluginName      VARCHAR(255)    NOT NULL,
    MacroName       VARCHAR(255)    NOT NULL,
    Disposition     VARCHAR(255)    NOT NULL
);

我意识到这确实是一项艰巨的工作,但我本以为可以用光标来完成。下面是我的存储过程。在我的 MySQL 客户端 (Navicat) 由于内存不足而停止响应之前,它向“Usage”表写入了大约 96,000 行。

有人能看出我做错了什么吗?任何帮助将不胜感激! ;)

DELIMITER //
CREATE PROCEDURE pluginanalysis()
BEGIN
  -- Declare variables used with cursor to fetch usage info
  DECLARE v_macrotype       INT(10)         DEFAULT 0;
  DECLARE v_pluginname      VARCHAR(255)    DEFAULT "";
  DECLARE v_macroname       VARCHAR(255)    DEFAULT "";
  DECLARE v_mask            VARCHAR(255)    DEFAULT "";
  DECLARE v_disposition     VARCHAR(255)    DEFAULT "";
  DECLARE v_num_rows        INT(10)         DEFAULT 0;
  DECLARE v_loop_counter    INT(10)         DEFAULT 0;
    DECLARE v_no_more_rows    BOOLEAN;

  -- Declare cursor "c" to populate Usage table with info about where macros are used
  DECLARE c CURSOR FOR 
    SELECT MacroType, PluginName, MacroName, Mask, Disposition FROM appfire_Plugins;
  -- Declare NOT FOUND handler  
  DECLARE CONTINUE HANDLER FOR NOT FOUND 
    SET v_no_more_rows = TRUE;  

  -- Open cursor "c"  
  OPEN c;
  SELECT FOUND_ROWS() INTO v_num_rows;

  SELECT 'Number of rows =', v_num_rows;

  get_usage_loop: LOOP
    FETCH c 
           INTO v_macrotype, 
                v_pluginname, 
                v_macroname, 
                v_mask, 
                v_disposition;

        -- Break out of the loop if there were no records or we've processed them all
        IF v_no_more_rows THEN
      CLOSE c;
      LEAVE get_usage_loop;
    END IF;

        INSERT INTO Usage (SpaceKey, PageTitle, ViewURL, MacroType, PluginName, MacroName, Disposition)
            SELECT SpaceKey,
                PageTitle,
                ViewURL,
                v_macrotype,
                v_pluginname,
                v_macroname,
                v_disposition
           FROM CurrentPages
           WHERE ContentBody LIKE v_mask;

          SET v_loop_counter = v_loop_counter + 1;

  END LOOP get_usage_loop;

    -- Show both counters; they should match if all rows were processed 
  SELECT v_num_rows, v_loop_counter;
END //
-- Restore standard delimiter (semicolon)
DELIMITER ;




-- Now call the stored procedure
CALL pluginanalysis();

最佳答案

在 MySQL 和 SQL Server 中,设置操作通常比使用游标更快。

我认为以下查询可以替换所有光标代码:

    INSERT INTO Usage(SpaceKey, PageTitle, ViewURL, MacroType, PluginName, MacroName, Disposition)
        SELECT cp.SpaceKey, cp.PageTitle, cp.ViewURL,
               ap.macrotype, ap.pluginname, ap.macroname, ap.disposition
       FROM Appfire_Plugins ap JOIN
            CurrentPages cp
            ON cp.ContentBody LIKE ap.mask;

关于MySQL 游标占用大量内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25233035/

相关文章:

android - 从数组中获取游标

Android 如何从SQLite 游标查询中获取返回值字符串并显示在Edittext 中?

mysql - 使用 JOIN 查询花费太多时间

mysql - SQL查询根据另一列中的唯一元素查找列中的公共(public)ID

mysql - 哪些 MySQL 数据库表包含 Magento 1.x 中商店的数据?

php - 从数组中删除重复值

sql - ORA-08103 在过程中使用全局临时表 DML(插入、更新、选择),选择光标到临时表显示错误对象不存在

jQuery CSS — 强制光标根据请求更改(不仅在请求后鼠标移动时)?

css - Windows XP 中两个光标相互重叠的问题

mysql - SQL 与 If 不同