写点什么

如何缓存存储过程的结果

  • 2014-03-31
  • 本文字数:1332 字

    阅读完需:约 4 分钟

Brent Ozar 是咨询公司 Brent Ozar Unlimited 的创始人和负责人,同时也是一名微软最有价值专家和 SQL Server DBA。他发表了一篇博文,介绍一种缓存存储过程结果的方案及应用场景。

在文章开头,他给出了这样一个场景:一家在线商店需要在每个物品的页面上显示用户买过的相关产品。他认为,在完美的世界中,这些数据应该在 Web/ 应用层缓存。但是,有时候,开发人员会构建存储过程来获取这类数据,而最终存储过程的调用过于频繁。

Brent 指出,对于这种已经使用了存储过程的情况,可以构建一个缓存供存储过程使用。

假如加入缓存层之前的代码如下:

复制代码
CREATE PROCEDURE dbo.usp_GetRelatedItems
@ItemID INT AS
BEGIN
SELECT RelatedItemID,RelatedItemName
FROM dbo.BigComplicatedView
WHERE SoldItemID=@ItemID;
END
GO

代码一:原来的存储过程

则加入缓存层之后的代码如下:

复制代码
CREATE PROCEDURE dbo.usp_GetRelatedItems
@ItemID INT AS
BEGIN
IF EXISTS(SELECT * FROM Cache.dbo.GetRelatedItems
WHERE ItemID=@ItemID)
SELECT *
FROM Cache.dbo.GetRelatedItems
WHERE ItemID=@ItemID
ELSE
SELECT RelatedItemID,RelatedItemName
FROM dbo.BigComplicatedView
WHERE SoldItemID=@ItemID;
END
GO

代码二:实现缓存(一)

代码二引入了一个新表 Cache.dbo.GetRelatedItems,其中 Cache 是新建的数据库。该表中的列比 usp_GetRelatedItems 的返回结果多了一个输入字段和一个 ID,其格式如下:

该表中的数据可以根据需要每天晚上或者每周进行一次 truncate。另外,在实际工作中实现这样一个方案时,他还会根据大量 A/B 性能测试的结果创建恰当的聚簇索引。

代码二并未对缓存表进行操作。如果数据没有缓存,其实需要将其插入缓存表,代码如下:

复制代码
CREATE PROCEDURE dbo.usp_GetRelatedItems
@ItemID INT AS
BEGIN
/* 查看待查找的记录是否已经缓存 */
IF NOT EXISTS(SELECT * FROM Cache.dbo.GetRelatedItems
WHERE ItemID=@ItemID)
BEGIN
/* 缓存中没有记录,因此插入缓存 */
INSERT INTO Cache.dbo.GetRelatedItems
(ItemID,RelatedItemID,RelatedItemName)
SELECT RelatedItemID,RelatedItemName
FROM dbo.BigComplicatedView
WHERE SoldItemID=@ItemID;
END
/* 从缓存中获取记录 */
SELECT *
FROM Cache.dbo.GetRelatedItems
WHERE ItemID=@ItemID
END
GO

代码三:实现缓存(二)

他承认,这种做法会增加 SQL Server 的写负载,但他只有在面临下面这些情况时才使用这种方案:

  • 操作极为密集但只读的存储过程
  • 调用非常频繁(每分钟几百或几千次)
  • 其结果变化频率少于每天一次(或者不关心实时精度)
  • 业务需要非常快的系统改进速度,没有时间等着开发人员实现一个缓存层

最后,他指出,这只是紧急情况下让业务恢复运行的一种创可贴式方案。另外,他还推荐了一些与缓存相关的资源,包括最快的查询是不用执行的那个选择缓存方式通过缓存让系统更好地运行。有兴趣的读者可以进一步阅读。


感谢包研对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2014-03-31 07:501739
用户头像

发布了 256 篇内容, 共 87.7 次阅读, 收获喜欢 12 次。

关注

评论

发布
暂无评论
发现更多内容

区块链赋能供应链金融|应用优势与四类常见模式

CECBC

区块链

食堂就餐卡系统设计

Griffenliu

Java中的String到底占用多大的内存空间?你所了解的可能都是错误的!!

冰河

Java 内存泄露 string 性能调优 内存溢出

容器化应用系统上生产的最佳实践

东风微鸣

Kubernetes 最佳实践 生产

容器开发运维人员的Linux操作机配置优化建议

东风微鸣

Kubernetes 最佳实践 k8s入门

微服务的理想与现实

京东科技开发者

云原生

为什么Java容器推荐使用ExitOnOutOfMemoryError而非HeapDumpOnOutOfMemoryError?

东风微鸣

Kubernetes 最佳实践 jvm调优

Java中String占用空间的评估标准

陈德伟

Java jdk 源码剖析

架构师训练营第 2 期第一周作业

井中人

Week 4学习总结

balsamspear

极客大学架构师训练营

商用密码与区块链共推数字经济发展

CECBC

网络安全 数字经济

终于,SM2国密算法被Linux内核社区接受了!

阿里云基础软件团队

mongodb源码实现、调优、最佳实践系列-Mongodb网络模块源码实现及性能调优(一)

杨亚洲(专注MongoDB及高性能中间件)

MySQL mongodb 中间件 架构师 分布式数据库mongodb

一致性 hash

garlic

极客大学架构师训练营

二十一、深入Python强大的装饰器

刘润森

Python

一文读懂线程池的工作原理(故事白话文)

捡田螺的小男孩

Java 面试 线程池 线程池工作原理

如果只推荐一本 Python 书,我要 Pick 它!

Python猫

Python 学习 编程 程序员 码农

如何基于消息中间件实现分布式事务?我想说的都在这儿了!!

冰河

分布式事务 微服务 分布式数据库 数据一致性 海量数据

架构师训练营第2期-第一周-学习总结

井中人

大明湖畔昇腾绽放,趵突泉里智能奔涌

脑极体

epoll服务器解析

菜鸟小sailor 🐕

数据安全无小事:揭秘华为云GaussDB(openGauss)全密态数据库

华为云开发者联盟

安全 数据 加密

在K8S Volume中使用 subPath

东风微鸣

Kubernetes 最佳实践

谁说AI看不懂视频?

华为云开发者联盟

视频 剪辑

socket编程

菜鸟小sailor 🐕

websocket

小熊派开发实践丨漫谈LiteOS之传感器移植

华为云开发者联盟

开发 IoT stm32

听说你会缓存?

架构师修行之路

redis 缓存 微服务

Week 4命题作业

balsamspear

极客大学架构师训练营

Vidyo产品给用户方带来了什么直接的便利

dwqcmo

音视频 集成架构 解决方案 智能硬件

关于编码

西贝

Java 编码

设计数据库集群读写分离并非易事

架构师修行之路

分布式 微服务

如何缓存存储过程的结果_语言 & 开发_马德奎_InfoQ精选文章