每次我选择MySQL函数时,它的执行时间都会增加



有点奇怪。我有一个函数一开始运行得很好,比如说,当选择返回值加上其他一些列时,执行15毫秒,获取10毫秒。但是,如果不断刷新同一个查询,查询的执行就会上升。所以先是15秒,然后是17秒,然后。。。我一路跑到900米。这主要是随着时间的推移而上升的获取,但执行也是如此。因此,在最后,它将是600毫秒的获取和300毫秒的执行。你知道发生了什么事吗?

函数。我只尝试了一个简单的IF/ELSEIF,但它在性能方面给出了完全相同的结果。

create function get_table(var_account_id int unsigned) returns varchar(20)
    reads sql data
BEGIN
    RETURN IF(
            (SELECT EXISTS(SELECT TRUE
                           FROM TableA
                           WHERE account_id = var_account_id
                             AND expiring_at > CURRENT_TIMESTAMP)), 'TableA',
            IF((SELECT EXISTS(SELECT TRUE
                              FROM TableB
                              WHERE account_id = var_account_id
                                AND expiring_at > CURRENT_TIMESTAMP)), 'TableB',
               IF((SELECT EXISTS(SELECT TRUE
                                 FROM TableC
                                 WHERE account_id = var_account_id
                                   AND expiring_at > CURRENT_TIMESTAMP)), 'TableC',
                  IF((SELECT EXISTS(SELECT TRUE
                                    FROM TableD
                                    WHERE account_id = var_account_id
                                      AND expiring_at > CURRENT_TIMESTAMP)), 'TableD',
                     NULL)
                   )));
END;

用var_account_id=1 运行一次后解释函数

9,SUBQUERY,TableD,,ref,"TableD_expiring_at_index,TableD_account_id_index",TableD_account_id_index,4,const,1,100,Using where
7,SUBQUERY,TableC,,ref,"TableC_account_id_index,TableC_expiring_at_index",TableC_account_id_index,4,const,1,5,Using where
5,SUBQUERY,TableB,,ref,"TableB_expiring_at_index,TableB_account_id_index",TableB_account_id_index,4,const,1,9.26,Using where
3,SUBQUERY,TableA,,ref,"TableA_expiring_at_index,TableA_account_id_index",TableA_account_id_index,4,const,1,100,Using where

在account_id和expiring_at上设置复合索引对没有任何影响

我运行一个类似的简单查询

SELECT TableXYZ.*, get_table(TableXYZ.account_id) AS some_value FROM TableXYZ LIMIT 500;

我在更复杂的查询中运行过它,但结果总是一样的,一开始很快,重新运行同一个SELECT后很慢,比如说连续30秒每秒5次。即使在我让MySQL冷却一段时间后,回来,第一次运行仍然是900ms。我相信它会继续上升。解决这个问题的唯一方法是在windows中重新启动mysql服务。

解释SELECT:

1,SIMPLE,TableXYZ,,ALL,,,,,695598,100,

如果重要的话,我会在Windows 10上运行这些,本地的。

听起来很疯狂。也许你可以避免子查询,这通常会导致性能问题

SELECT X.tabName
FROM (
SELECT 'TableA' as tabName, 1 as tabNr, account_id, expiring_at FROM TableA WHERE account_id = var_account_id AND expiring_at > CURRENT_TIMESTAMP
UNION
SELECT 'TableB' as tabName, 2 as tabNr, account_id, expiring_at FROM TableB WHERE account_id = var_account_id AND expiring_at > CURRENT_TIMESTAMP
UNION
...
    ) X ORDER BY tabNr LIMIT 1

如果因为有非常大的表而想要避免并集,那么为什么不在函数中使用控制流呢?

DECLARE tabName VARCHAR(50);
SET tabName := SELECT 'TableA' FROM TableA WHERE account_id = var_account_id AND expiring_at > CURRENT_TIMESTAMP;
IF (tabName IS NULL) THEN
   SET tabName := SELECT 'TableB' FROM TableB WHERE account_id = var_account_id AND expiring_at > CURRENT_TIMESTAMP;
END IF;
and so on...
RETURN tabName;
RETURN COALESCE(
    IF (EXISTS(...), "A", NULL),
    IF (EXISTS(...), "B", NULL),
    IF (EXISTS(...), "C", NULL),
    IF (EXISTS(...), "D", NULL),
    IF (EXISTS(...), "E", NULL)
               )

其中...为,例如:

SELECT 1
    FROM TableA
    WHERE account_id = var_account_id
      AND expiring_at > CURRENT_TIMESTAMP

注:

  • 请确保表*中有此索引:INDEX(account_id, expired_at)(按顺序(
  • CCD_ 3在找到匹配行的地方停止。(一个提议的解决方案未能停止,因此需要更长的时间。(
  • COALESCE()不需要评估其所有参数。(UNION确实如此。(
  • (不,我不明白为什么它会越来越慢。希望我的配方会一直更快。(

最新更新