【问题标题】:MySQL function execution time increases everytime I SELECT it每次我选择它时,MySQL 函数的执行时间都会增加
【发布时间】:2023-03-11 05:14:01
【问题描述】:

有点奇怪。我有一个函数起初运行得非常好,比如在选择返回值和其他一些列时执行 15ms 和 10ms 获取。但是,如果不断刷新相同的查询,一遍又一遍,查询的执行就会上升。所以首先是 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 后变慢,比如说每秒 5 次,持续 30 秒。即使我让 MySQL 冷却了一会儿,回来,第一次运行仍然是 900 毫秒。而且我相信它可以继续上涨。解决此问题的唯一方法是在 windows 中重新启动 mysql 服务。

SELECT 的解释:

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

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

【问题讨论】:

  • 确实很奇怪。难道是操作系统以某种方式限制了数据库服务? (我猜这应该会使其他查询随着时间的推移变慢)
  • 奇怪!什么MySQL版本? a、b、c、d、e 表有多大?请edit您的问题。

标签: mysql function optimization query-optimization mysql-function


【解决方案1】:

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

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;

【讨论】:

  • 我尝试了第一个,虽然时间没有随着时间的推移而增加,但它很慢,所以它从 1.3 秒开始,在调用函数时(几乎使用相同的确切代码) 在 300 毫秒内完成,但随后它开始上升。第二种方法我也试过。相同的性能,但它会随着时间的推移而上升。与我帖子中的代码相同。我迷路了,我以前从未见过这种情况。
【解决方案2】:
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)(按此顺序)。
  • EXISTS() 在找到匹配行的地方停止。 (一个提议的解决方案未能停止,因此花费了更长的时间。)
  • COALESCE() 不需要评估其所有参数。 (UNION 会。)
  • (不,我不明白为什么它会越来越慢。希望我的公式会一直更快。)

【讨论】:

    猜你喜欢
    • 2023-03-29
    • 2019-05-12
    • 2022-01-20
    • 1970-01-01
    • 2018-11-04
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多