知识卡片
存储过程省下的是网络与解析开销,代价是复制诡异和缓存浪费
内容
存储过程/函数是否”更快”不能一概而论,而要看它省下了什么、又付出了
什么。它真正的性能收益来自省掉网络往返和解析/优化开销:一个存储过程
调用可以在服务器内部完成本来需要很多次小查询才能做的事,如果这些小
查询本身很轻,那么每次查询固有的网络通信、SQL解析、优化器开销占比
就会很高,把它们打包进一次存储过程调用能显著摊薄这部分固定成本——
书中一百万行数据的写入基准测试里,存储过程用101秒完成,客户端逐条
插入要279秒,差距主要就来自省下的网络和解析开销,而不是”存储过程本身
执行更快”。但这个收益是有代价的,且代价不体现在单次调用的响应时间上:
优化器无法用DETERMINISTIC这类声明去优化同一查询里多次调用存储函数
的情况,也无法评估存储函数本身的执行成本,这意味着优化器在涉及存储
代码时基本是”盲选”执行计划;执行计划缓存是按连接维度隔离的,多个连接
调用同一个存储过程时,同一份执行计划会被反复独立缓存,白白浪费缓存
空间;存储程序和基于语句的复制是”诡异组合”——如果直接复制对存储过程
的调用而不是它实际改变的数据,主备之间执行结果可能不一致,这也是
MySQL后来引入基于行的复制来缓解这个问题的原因之一。这说明”要不要用
存储过程”本质上是在”减少单次交互的固定开销”和”给优化器、复制、缓存
系统增加不透明的黑盒”之间做权衡,而不是简单的”存储过程天生快或慢”。
参考来源
- 位置:《高性能MySQL:第3版》第7章"MySQL高级特性"7.4.1节"存储过程和
函数"(源文件:_epub-src/OEBPS/Text/part0014.xhtml)
- 结论依据:原文明确"优化器无法使用关键字DETERMINISTIC来优化单个
查询中多次调用存储函数的情况。优化器无法评估存储函数的执行成本。
每个连接都有独立的存储过程的执行计划缓存……存储程序和复制是一组
诡异组合",并给出存储过程101秒对比客户端逐条插入279秒的基准测试
数据,直接支撑"收益来自省下网络/解析开销,代价是优化器盲选/缓存
浪费/复制风险"的结论。
- 原始内容:可以看到存储过程要快很多,很大程度因为它无须网络通信
开销、解析开销和优化器开销等……存储程序和复制是一组诡异组合。