似乎在MySQL查询中调用FUNCTION
的速度非常慢,那么我们有什么办法来解决这个问题呢?
是否存在像C / C ++这样的“内联”函数(= MERGE
算法不适用于VIEW
而是适用于FUNCTION
)?
还有其他方法可以加快FUNCTION
调用本身(例如:在展示中,很难固定函数本身,而缓慢来自其调用,而不是其内容) ?
示例
我创建一个整数表(~500k),并使用SELECT
子句对其进行WHERE
。这运行大约1秒钟。然后,我执行相同的SELECT
,但将WHERE
微积分放在FUNCTION
中,执行时间超过10倍(约30秒)。
有没有办法继续使用FUNCTION
(因为在实践中,我在WHERE
但是在不同的列上执行相同的微积分,所以就像拥有WHERE x blabla AND y blabla AND z blabla...
所以我想要将所有blabla
合并到一个函数中而不会耗尽执行时间?
CREATE TABLE IF NOT EXISTS `integers` (
`n` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`n`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
TRUNCATE TABLE integers;
INSERT INTO integers (n) VALUES (0),(1),(2),(3),(5);
INSERT IGNORE INTO integers (n) (
SELECT x.n+5*(y.n+5*(z.n))
FROM integers AS x
INNER JOIN integers as y
INNER JOIN integers as z
);
INSERT IGNORE INTO integers (n) (
SELECT x.n+95*(y.n+95*(z.n))
FROM integers AS x
INNER JOIN integers as y
INNER JOIN integers as z
WHERE y.n > 0 OR z.n > 0
);
SELECT COUNT(*) FROM integers;
-- Shows it has about 568k rows
DROP FUNCTION IF EXISTS `test_speed`;
DELIMITER $$
CREATE FUNCTION `test_speed`(
`n` INT UNSIGNED
)
RETURNS BOOLEAN
LANGUAGE SQL
DETERMINISTIC
NO SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
RETURN (n % 128 = 0);
END$$
DELIMITER ;
SET @timer := UNIX_TIMESTAMP();
SELECT *, (i.n+1e6*j.n)
FROM integers AS i
INNER JOIN integers AS j ON j.n < 32
WHERE (i.n+1e6*j.n) % 128 = 0
;
-- Takes like 1 second
SET @d1 := UNIX_TIMESTAMP() - @timer;
SET @timer := UNIX_TIMESTAMP();
SELECT *, (i.n+1e6*j.n)
FROM integers AS i
INNER JOIN integers AS j ON j.n < 32
WHERE test_speed(i.n+1e6*j.n)
;
-- Takes like 30 seconds
SET @d2 := UNIX_TIMESTAMP() - @timer;
SELECT @d1, @d2;
-- Shows the durations
请注意,两个查询都具有完全相同的EXPLAIN
:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE j \N range PRIMARY PRIMARY 4 \N 23 100.00 Using where; Using index
1 SIMPLE i \N index \N PRIMARY 4 \N 568625 100.00 Using where; Using index; Using join buffer (Block Nested Loop)
但FUNCTION
来电的第二次调用非常慢......