2011-10-24 244 views
5

我一直在试图弄清楚我有一系列查询出了什么问题,而现在我只是感到困惑。MySQL查询在直接运行时速度很快,但在以存储过程运行时速度很慢

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

有使用SELECT与子查询,终于另一UPDATE只有一个“微小”的问题,它的第一个简单的UPDATE,那么INSERT。手工一起运行这些查询,总共执行时间为0.057秒,不算太破旧。

现在,我尝试创建一个带有这些查询的存储过程以及五个输入变量,我运行此过程,并在第一次尝试时花费了47.096秒,随后调用它显示类似的执行时间(35到50秒)。从MySQL工作台运行单个查询仍然显示小于0.1s的执行时间

实际上这些查询没有什么奇特的东西,那么为什么存储过程需要永久执行,而查询本身只能执行几分之一秒?是否有某种我在此错过的MySQL特性?

进一步的测试结果:

看来,如果我跑在MySQL Workbench中的查询,但使用变量,而不是仅仅把变量的值在查询运行就像存储过程一样慢。所以我试着改变存储过程来使用静态值而不是变量,并且突然快速地运行。显然,由于某种原因,使用变量会使其运行速度非常慢(例如,当我在查询中直接使用变量值时,第一个UPDATE查询从三个变量的约0.98s变为0.04-0.05s,无论它是在存储过程中或直接运行查询)。

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

+0

我们需要看到一些代码。在声明/处理变量时,第一个疯狂的猜测会是奇怪的事情......但是,如果没有看到一些代码,这是一个完全*狂野的猜测。 –

+0

正如我所说的,非常简单的查询运行真的很快,只是'UPDATE表SET列=变量WHERE othercolumn> = othervariable或othercolumn = yetanothervar'类型的东西。并且这些变量在常规的'IN varname COLUMNTYPE(SIZE)'表单中声明为存储过程的参数。令我感到困惑的是,没有什么奇怪或缓慢的(是的,我避免显示代码,因为我的老板可能会因为我这样做而感到不安)。 – mludd

+0

我可以提到删除除UPDATE之外的所有查询(本身运行时间小于0.05s,然后运行存储过程仍然会给出1s左右的执行时间,上面的注释很简单地描述了复杂的是'UPDATE'是... – mludd

回答

0

Upvote为一个非常有趣和重要的问题。我发现this discussion是存储过程可能很慢的一些原因。我很想看到读者对它的反应。

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

+0

你的答案在这里有一个死链接,我尽我所能纠正它,但我不得不引用archive.org。我看到的任何“重复”消息都没有包括Ronald Bradford的补充。 –

0

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

所以,不是真正的解决方案或解释发生了什么,但至少它的作品。

3

我有一个类似的问题。运行一个mysql例程非常慢。 但一位同事帮助了我。 问题是AUTOCOMMIT是真的; 因此,每个插入和选择都创建一个完整的事务。 然后我跑我的

SET autocommit=0; 

在开始和

SET autocommit=1;      

常规末。性能从近500S去4S

5

我有同样的问题。经过一段时间的研究后,我发现问题在于MySQL比较文本时的排序问题。

TL; DR:该表是在一个归类中创建的,而MySQL“认为”变量是在另一个归类中。因此,MySQL不能使用用于查询的索引。

在我的情况下,该表与(LATIN1latin1_swedish_ci)整理创建。为了使MySQL使用索引,我从

UPDATE ... WHERE mycolumn = myvariable 

在存储过程中改变where子句

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; 

其中(LATIN1latin1_swedish_ci)是一样的科拉这是我的表A创建。

要检查是否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

0

的东西,我们跨越今天,让程序慢,即使他们跑得非常快,直接查询跑,是具有与列名相同的参数(或者可能是可变的)名称。简短版本是,不要使用与查询中使用它的列中的某一列相同的参数名称。举例来说,如果你有一个域名为account_id和一个名为相同的参数,将其更改为类似in_account_id和你的运行时间可以从几秒到百分之一秒。

相关问题