【问题标题】:MySQL queries are fast when run directly but really slow when run as stored procMySQL 查询在直接运行时很快,但在作为存储过程运行时非常慢
【发布时间】:2011-12-14 00:13:49
【问题描述】:

我一直试图弄清楚我收到的一组查询出了什么问题,但我现在很困惑。

它应该在一个由 GUI 应用程序调用的存储过程中。

只有一个“小”问题,首先是一个简单的UPDATE,然后是使用SELECT 和子选择的INSERT,最后是另一个UPDATE。手动一起运行这些查询,我得到的总执行时间为 0.057 秒,不算太简陋。

现在,我尝试创建一个存储过程,其中包含这些查询和五个输入变量,我运行此过程,第一次尝试花费了 47.096 秒,随后对其调用显示了相似的执行时间(35 到 50 秒)。从 MySQL Workbench 运行单个查询仍然显示不到 0.1 秒的执行时间

这些查询真的没有什么花哨的,那么为什么存储过程需要很长时间才能执行,而查询本身只需要几分之一秒呢?我在这里缺少某种 MySQL 特性吗?

其他测试结果:

似乎如果我在 MySQL Workbench 中运行查询但使用变量而不是仅仅将变量的值放入查询中,它的运行速度与存储过程一样慢。所以我尝试将存储过程更改为只使用静态值而不是变量,然后它突然运行得非常快。显然,由于某种原因,使用变量使其运行速度极慢(例如,当我直接在查询中使用变量的值时,第一个 UPDATE 查询从三个变量的大约 0.98 秒变为 0.04-0.05 秒,而不管如果它在存储过程中或直接运行查询)。

所以,问题不在于存储过程,而与我对变量的使用有关(这是不可避免的)。

【问题讨论】:

  • 我们需要查看一些代码。第一个疯狂的猜测会是你在声明/处理变量时所做的一些奇怪的事情......但这是一个完全疯狂没有看到一些代码的猜测。
  • 正如我所说,非常简单的查询可以自行运行非常快,只需 UPDATE table SET column = variable WHERE othercolumn >= othervariable OR othercolumn = yetanothervar 输入内容。并且变量以常规IN varname COLUMNTYPE(SIZE) 形式声明为存储过程的参数。让我感到困惑的是,没有什么奇怪或缓慢的(是的,我避免显示代码是因为我的老板可能对我这样做感到恼火)。
  • 我可以提一下,除了第一个 UPDATE 查询(它本身运行时间不到 0.05 秒,然后运行存储的 proc 仍然给出大约 1 秒的执行时间,上面的评论是非常恰当地描述了 UPDATE 的复杂程度......

标签: mysql sql stored-procedures


【解决方案1】:

我遇到了同样的问题。研究了一会,发现问题出在 MySQL 比较文本时的排序问题。

TL;DR:该表是在一个排序规则中创建的,而 MySQL“认为”该变量是在另一个排序规则中。因此,MySQL 无法使用用于查询的索引。

就我而言,该表是使用 (latin1, latin1_swedish_ci) 排序规则创建的。为了让 MySQL 使用索引,我不得不将存储过程中的 where 子句从

    UPDATE ... WHERE mycolumn = myvariable

到

    UPDATE ... WHERE mycolumn = 
        convert(myvariable using latin1) collate latin1_swedish_ci

更改后的存储过程如下所示:

    CREATE PROCEDURE foo.'bar'()
    BEGIN
        UPDATE mytable SET mycolumn1 = variable1
        WHERE mycolumn2 = 
            convert(variable2 using latin1) collate latin1_swedish_ci
    END;

其中 (latin1, latin1_swedish_ci) 与创建我的 tableA 时使用的排序规则相同。

要检查 MySQL 是否使用索引,您可以更改存储过程以运行 explain 语句,如下所示:

    CREATE PROCEDURE foo.'bar'()
    BEGIN
        EXPLAIN SELECT * FROM table WHERE mycolumn2 = variable2
    END;

在我的例子中,explain 结果表明在执行查询期间没有使用索引。

请注意,当您单独运行查询时,MySQL 可能会使用索引,但仍不会将索引用于存储过程中的同一查询,这可能是因为 MySQL 在另一个排序规则中看到了该变量。

可以在此处找到有关排序规则问题的更多信息: http://lowleveldesign.wordpress.com/2013/07/19/diagnosing-collation-issue-mysql-stored-procedure/ 备份链接: http://www.codeproject.com/Articles/623272/Diagnosing-a-collation-issue-in-a-MySQL-stored-pro

【讨论】:

    【解决方案2】:

    我遇到了类似的问题。 运行 mysql 例程非常慢。 但是一位同事帮助了我。 问题是 AUTOCOMMIT 是真的; 所以每次插入和选择都在创建一个完整的事务。 然后我用

    运行我的例程
    SET autocommit=0; 
    

    在开头和

    SET autocommit=1;                    
    

    最后。性能从近500秒到4秒

    【讨论】:

    • 酷,你在程序中设置了这个吗?我在游标中有许多插入/选择操作(有百万条记录),我应该在 LOOP 之外设置吗?
    【解决方案3】:

    因为我不想浪费太多时间试图弄清楚为什么在我的存储过程中使用变量会使它们变得非常慢,所以我决定采用一些人认为非常丑陋的修复程序。我只是直接从我的应用程序的数据访问层执行每个查询。不是最漂亮的方法(因为这个应用程序的许多其他东西都使用存储过程)但它可以工作,现在用户不必等待 40 多秒来执行某些操作,因为它们几乎立即发生。

    因此,并不是真正的解决方案或对正在发生的事情的解释,但至少它有效。

    【讨论】:

      【解决方案4】:

      为一个非常有趣且重要的问题投票。我发现了this discussion 存储过程可能很慢的一些原因。我很想看看读者对此的反应。

      我从交换中获得的主要建议:它有助于添加更多索引。

      【讨论】:

      • 您在此处的回答有死链接。我尽我所能纠正了它,但我不得不参考archive.org。我看到的“重复”来源中没有一个包括 Ronald Bradford 的补充。
      【解决方案5】:

      我们今天遇到的一些让过程变慢的事情,即使它们作为直接查询运行得非常快,也就是参数(或者,可能是变量)名称与列名相同。简短的版本是,不要使用与查询中将使用它的列之一相同的参数名称。例如,如果您有一个名为 account_id 的字段和一个名称相同的参数,请将其更改为 in_account_id 之类的内容,您的运行时间可以从几秒到百分之一秒。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-27
        • 2016-12-17
        • 2012-06-13
        • 1970-01-01
        • 2010-10-13
        • 1970-01-01
        • 2011-06-09
        • 1970-01-01
        相关资源
        最近更新 更多