我在MySQL中有一个查询,它在表的每一行上运行一个存储函数,然后在返回前10行之前按函数的结果对行进行排序。
SELECT rowId, MyFunction(x, y, constX, constY) AS funResult
FROM myTable
ORDER BY funResult DESC
LIMIT 10
问题是在10,000行的表上运行需要几秒钟,这太慢了。函数的结果无法计算并存储为表中的另一行,因为它采用PHP给出的常量,并且每次运行查询时都不同。
函数本身的速度不是问题,因为删除ORDER BY funResult DESC LIMIT 10
意味着查询在不到0.01秒的时间内运行。
问题必须是对行进行排序 - 考虑到只需要前10行这一事实,有没有办法可以更快地完成这一过程?
更新
使用的简化函数计算每一行与指定点之间的距离(其中LAT_B和LON_B是取决于查询的常量):
CREATE FUNCTION MyFunction(LAT_A float, LON_A float, LAT_B float, LON_B float)
RETURNS double
DETERMINISTIC
BEGIN
DECLARE tempCalc DOUBLE;
SET tempCalc = 3956 * 2 * ASIN(SQRT( POWER(SIN((LAT_A -abs( LAT_B)) * pi()/180 / 2),2)
+ COS(LAT_A * pi()/180 ) * COS( abs(LAT_B) * pi()/180)
* POWER(SIN((LON_A - LON_B)
* pi()/180 / 2), 2) ));
RETURN tempCalc;
END
答案 0 :(得分:3)
在您的存储过程中合并排序 定义/逻辑。如果您的存储过程中的调用SQL选择执行排序并限制。 - 这意味着您不会在存储过程中生成10,000行,只是为了求助它们。此外,如果表具有索引,则SQL select中的原始排序可能会快得多。
验证您的表格中是否使用了索引。 - 索引会使您在桌面上选择时更快地执行排序。
请向我们提供功能定义,以便更方便地为您提供帮助。
最后,尝试移动您的订单并直接限制您的功能,而不是稍后执行。您的函数可以直接返回10个结果并准备就绪。 如果你愿意,可以创建两个函数 - 一个返回完整的结果,另一个返回它们有限和排序。
看到你的功能后,很明显你试图按计算值排序。按计算值排序非常慢,如下所述:
我正在考虑如何根据col1或col2“预处理/订购”您的数据,以加快结果的最终排序。如果col1和col2是表的列,而funResult是一个可以绘制的数学函数,其中一个对函数返回值有更大的影响....
最后,如果col1和col2是myTable的列,你不需要使用存储的函数但可以查询,但这不会产生很大的差异......你的主要问题是通过计算函数排序:
SELECT rowId, ((col1-INPUT_CONST)*2)+(col2*3) AS funResult
FROM myTable
ORDER BY funResult DESC
LIMIT 10
在挖掘排序问题后计算距离我发现已经在下面的链接中非常有效地询问并解决了这个问题。关于按计算值排序,作为按计算值排序,它本身就很慢。请参阅以下两个链接以获取其他帮助:
最后,最接近您答案的是: 的 https://stackoverflow.com/a/4180065/1688441 强>
答案 1 :(得分:1)
我猜你的问题 是你执行函数的时间。如果您执行此查询:
SELECT rowId, MyFunction(col1, col2, constant) AS funResult
FROM myTable
LIMIT 10
数据库必须:
相反,如果您执行此查询:
SELECT rowId, MyFunction(col1, col2, constant) AS funResult
FROM myTable
ORDER BY funResult DESC
LIMIT 10
数据库必须
因此,要真正了解您的函数是否是瓶颈,您应确保实际计算两个查询的所有10000行的函数结果,并检查差异是否仍然存在。
答案 2 :(得分:1)
扩展你的职能:
MyFunction(col1, col2, constant) = (col1 - constant) * 2.0 + col2 * 3.0 = 2*col1 + 3*col2 - 2*constant
因此,按MyFunction(col1, col2, constant)
排序相当于按2*col1 + 3*col2
排序,无论提供的常数如何。因此,您可以将该计算的结果缓存在新的索引列中:
ALTER TABLE myTable
ADD COLUMN tmpResult FLOAT,
ADD INDEX (tmpResult);
CREATE TRIGGER ins BEFORE INSERT ON myTable FOR EACH ROW
SET NEW.tmpResult := 2*NEW.col1 + 3*NEW.col2;
CREATE TRIGGER upd BEFORE UPDATE ON myTable FOR EACH ROW
SET NEW.tmpResult := 2*NEW.col1 + 3*NEW.col2;
UPDATE myTable SET tmpResult = 2*col1 + 3*col2;
然后您的SELECT
变为:
SELECT rowId, tmpResult - 2*constant AS funResult
FROM myTable
ORDER BY tmpResult DESC
LIMIT 10
答案 3 :(得分:1)
实际上,在mysql中实际上要快得多
select * from database order by 3956 * 2 * ASIN(SQRT( POWER(SIN((LAT_A -abs( LAT_B)) * pi()/180 / 2),2) + COS(LAT_A * pi()/180 ) * COS( abs(LAT_B) * pi()/180) * POWER(SIN((LON_A - LON_B) * pi()/180 / 2), 2) ));
比通过自定义功能订购。
它很难看但很快。
尝试对其进行解释。 出于某种原因,mysql在涉及函数时使用临时表,但在没有数学时则使用临时表。
答案 4 :(得分:0)
试试这个
SELECT rowId, MyFunction(col1, col2, constant) AS funResult
FROM myTable
ORDER BY MyFunction(col1, col2, constant) DESC
LIMIT 10