如何在不含数据检索的情况下为数据库函数调用计时?
单独统计函数调用耗时(排除数据检索开销)
你想统计myFunc被调用1亿次的耗时,但又不想包含大量数据返回的检索开销,先分析你提到的两种思路的问题:
SELECT myFunc(x) FROM my100MRowTable LIMIT 0:完全不可行,LIMIT 0会让数据库直接返回空结果集,根本不会去执行任何一行的myFunc(x)调用。SELECT myFunc(x) FROM my100MRowTable GROUP BY "for-testing":这个方法不稳定,不同数据库的优化器可能会偷懒——因为分组键是常量,有些数据库只会计算一次myFunc(x)就返回结果,不会遍历所有1亿行,达不到测试目的。
下面是两种可靠的方案:
方案1:用聚合函数强制遍历全表并调用函数
使用COUNT或SUM这类聚合函数,数据库必须遍历每一行调用myFunc(x),最终只返回一个聚合结果,彻底避免大量数据传输的开销:
SELECT COUNT(myFunc(x)) FROM my100MRowTable;
如果myFunc返回数值类型,也可以用SUM:
SELECT SUM(myFunc(x)) FROM my100MRowTable;
这样既保证了每一行都触发myFunc调用,又不会有数据检索的IO开销,计时结果就是纯函数调用的耗时。
方案2:带条件的COUNT,避免NULL值影响
如果myFunc可能返回NULL,COUNT(myFunc(x))会忽略这些NULL行,导致调用次数不足1亿次。可以用下面的写法确保每行都被统计:
SELECT COUNT(*) FROM my100MRowTable WHERE myFunc(x) IS NOT NULL OR myFunc(x) IS NULL;
不管myFunc返回什么,这个条件都会成立,数据库必须调用函数判断,同时COUNT(*)会统计所有行,保证1亿次调用。
额外注意:防止函数结果被缓存
如果myFunc是确定性函数(相同输入返回相同结果),部分数据库会缓存函数结果,导致实际调用次数少于1亿次。可以给函数加一个每行唯一的参数(比如主键id),破坏缓存条件:
SELECT COUNT(myFunc(x, id)) FROM my100MRowTable;
这样数据库无法复用之前的函数结果,必须对每一行执行一次调用。
内容的提问来源于stack exchange,提问作者David542
相关产品推荐
相关产品推荐

