SQL查询缓存

article/2025/10/6 9:35:54
适合读者
本教程适合于那些对缓存SQL查询以减少数据库连接与执行的负载、提高脚本性能感兴趣的PHP程序员。
概述
许多站点使用数据库作为站点数据存储的容器。数据库包含了产器信息、目录结构、文章或者留言本,有些数据很可能是完全静态的,这些将会从一个缓存系统中得到的极大好处。
这样一个系统通过把SQL查询的结果缓存到系统的一个文件中存储,从而阻止连接数据库,构造查询与取得返回结果而提高了响应时间。
有些系统数据库并不是放在WEB服务器上的,这样需要一个远程连接(TCP或者其它类似的),或者从数据库中获取大量的数据,这样你得忍受更多时间,这决定于系统响应时间与资源利用。
前提
本教程使用MySQL作为数据库。你需要安装MySQL(www.mysql.com下载是有效的)和激活PHP MYSQL扩展(默认情况是激活的)。
由于要查询数据库,你需要知识一些SQL(结构化查询语言)的基本常识。
缓存SQL查询结果
为什么要缓存查询结果?
缓存查询结果能极大地改进脚本执行时间和资源需求。
缓存SQL查询结果也允许你通过后期处理数据。如果你用文件缓存去存储全部脚本的输出结果(HTML输出),这样可能是行不通的。
当你执行一个SQL查询时,点典的处理过程是:
<!--[if !supportLists]--> l        <!--[endif]--> 连接数据库
<!--[if !supportLists]--> l        <!--[endif]--> 准备SQL查询
<!--[if !supportLists]--> l        <!--[endif]--> 发送查询到数据库
<!--[if !supportLists]--> l        <!--[endif]--> 取得返回结果
<!--[if !supportLists]--> l        <!--[endif]--> 关闭数据库连接
以上方法非常占用资源并且相反的影响了脚本的性能。只能通过取得的大量返回数据和数据库服务器的位置这二个要素来相互协调。尽管持续连接可以改进连接数据库时的负载,但非常耗费内存资源,如果获取的是大量的数据,那么存储的全部时间会非常短暂。
创建一条SQL查询:
SQL( 结构化查询语言)查询被用作操作数据库及它内容的接口。SQL可用于定义和编辑表的结构,插入数据到表,更新或删除表中的信息。
SQL 是用于与数据通讯的语言,在大多数PHP数据库扩展(MySQL,ODBC,Oracle等)通过传递SQL查询到数据库中来管理整个过程。
本教程中,仅仅用select语言来获取数据库中的数据。这些数据将被缓存,之后将用作数据源。
决定什么时候更新缓存:
根据程序的需要,缓存可以采取多种形式。最常见的3种方式是:
<!--[if !supportLists]--> l        <!--[endif]--> 时间触发缓存(过期的时间戳)
<!--[if !supportLists]--> l        <!--[endif]--> 内容改变触发缓存(发现数据改变后,相应地更新缓存)
<!--[if !supportLists]--> l        <!--[endif]--> 人工触发缓存(人工的方式告知系统信息超期并且强制产生新的缓存)
你的缓存需求可能是以上原理的一个或多个的综合。本教程将讨论时间触发方式。然而,在一个全面的缓存机制中,3种方式的综合将被使用。
缓存结果:
基本的缓存是用PHP的两个函数serialize()和unserialize()(译注:这二个函数分别代表序列化与反序列化)。
函数serialize()用于存储PHP的值,它能保证不失去这些值的类型和结构。
事实上,PHP的session扩展是用序列化过的变量,把session变量($_SESSION)存储在系统的一个文件中。
函数unserialize()与以上操作相反并且使序列化过的字符串返回到它原来的结构和数据内容。
在本例中,以一个电子商务商店为例。商店有2个基本表,categories和products(此处为原始数据库表名).product表可能每天都在变化,categories仍然是不变静止的。
要显示产品,你可以用一个输出缓存脚本来存储输出的HTML结果到一个文件中。然而categories表可能需要后期处理。例如,所有的目录通过变量category_id(通过$_REQUEST['category_id']来取得)被显示,你可能希望高亮当前被选择的目录。
表categories结构
Field
Type 
Key
Extra
category_id
category_name
category_description
int(10) unsigned
varchar(255)
text
PRI
auto_incremen
 
 
在本例中,通过时间触发缓存技术被运用,设定一段时间后让其缓存SQL输出过期。在此特殊的例子中,定一段时间为24小时。
序列化例子:
<!--[if !supportLists]--> l        <!--[endif]--> 连接数据库
<!--[if !supportLists]--> l        <!--[endif]--> 执行查询
<!--[if !supportLists]--> l        <!--[endif]--> 取得所有结果构成一个数组以便后面你可以访问
<!--[if !supportLists]--> l        <!--[endif]--> 序列化数组
<!--[if !supportLists]--> l        <!--[endif]--> 保存序列化过的数组到文件中
$file   =   ' sql_cache.txt '
$link   =   mysql_connect ( ' localhost ' , ' username ' , ' password '
    or 
die  ( mysql_error ()); 
mysql_select_db ( ' shop '
    or 
die  ( mysql_error ()); 
/*  构造SQL查询  */  
$query   =   " SELECT * FROM categories "
$result   =   mysql_query ( $query
    or 
die  ( mysql_error ()); 
while  ( $record   =   mysql_fetch_array ( $result ) )

   
$records []  =   $record

$OUTPUT   =   serialize ( $records ); 
$fp   =   fopen ( $file , " w " );  //  以写权限的方式打开文件 
fputs ( $fp ,   $OUTPUT ); 
fclose ( $fp ); 
查看sql_cache.txt文件,里面的内容可能类似这样的:
a:1:{i:0;a:6:{i:0;s:1:"1";s:11:"category_id";s:1:"1";i:1;s:9:"Computers";s:13:"category_name";s:9:
"Computers" ;i:2;s:25:"Description for computers";s:20:"category_description"
;s:25:"Description for computers";}}
这个输出是它的变量和类型的内部表现形式。假若你用mysql_fetch_array()函数返回数字索引的数组和一个关联的数组(这就是为什么数据看起来像是发生了两次),一个是数字索引,另一个是字符串索引。
使用缓存:
要用缓存,你需要用函数unserialize()来使数据还原成原始格式与类型。
你可以用file_get_contents()这个函数来读取sql_cache.txt文件的内容,把它赋给一个变量。
请注意:这个函数在PHP4.3.0及以上版本有效。若你使用的是一个老版本的PHP,一个简单的方法是用file()函数(读整个文件到一个数组,每行变成一个数组)。implode()函数用于把数组的各元素连接成一个字符串然后使用unserialize()反序列化。
// file_get_contents() 适合于for PHP < 4.3.0
$file = 'sql_cache.txt';
$records = unserialize(implode('',file($file)));
现在你可以通过$records数组并且取得原始查询的数据:
foreach ($records as $id=>$row) {
    print $row['category_name']."<br>";
}
注意$records是数组(一个包含了查询结果的数字索引列——每行是一个数字和一个字符串...真是混乱)的一排。
把它们放在一块:
基于本例子中的时间来决定是否缓存。如果文件修改的时间戳比当前时间戳减去过期时间戳大,那么就用缓存,否则更新缓存。
<!--[if !supportLists]--> l        <!--[endif]--> 检查文件是否存在并且时间戳小于设置的过期时间
<!--[if !supportLists]--> l        <!--[endif]--> 获取存储在缓存文件中的记录或者更新缓存文件
<? php 
$file   =   ' sql_cache.txt '
$expire   =   86400 //  24 小时 (单位:秒) 
if  ( file_exists ( $file &&  
filemtime ( $file >  ( time ()  -   $expire )) 

    
//  取得缓存中的记录
     $records   =   unserialize ( file_get_contents ( $file )); 
else  { 
    
//  通过 serialize() 函数创建缓存 



?>
附加其它可能的:
<!--[if !supportLists]--> l        <!--[endif]--> 把缓存结果存储在共享内存中以获取更快的速度
<!--[if !supportLists]--> l        <!--[endif]--> 增加一个功能随机地运行SQL查询并且检查是否输出与缓存输出一致。如果不一致,则更新缓存(本函数运行次数的概率可以定为1/100)。通过哈希算法(如MD5())可以协助判断字符串或者文件是否改变。
<!--[if !supportLists]--> l        <!--[endif]--> 增加一个管理员的功能,人工的删除这个缓存文件,以强制更新缓存(如file_exists()函数返回false时)。你可以用函数unlink()删除文件。
脚本:
<? php
$file   =   ' sql_cache.txt '
$expire   =   86400 //  24 小时 
if  ( file_exists ( $file &&  
    
filemtime ( $file >  ( time ()  -   $expire )) { 
    
$records   =   unserialize ( file_get_contents ( $file )); 
else  { 
    
$link   =   mysql_connect ( ' localhost ' , ' username ' , ' password '
        or 
die  ( mysql_error ()); 
    
mysql_select_db ( ' shop '
        or 
die  ( mysql_error ()); 
    
/*  构造SQL查询  */  
    
$query   =   " SELECT * FROM categories "
    
$result   =   mysql_query ( $query
        or 
die  ( mysql_error ()); 
    
while  ( $record   =   mysql_fetch_array ( $result ) ) { 
        
$records []  =   $record
    } 
    
$OUTPUT   =   serialize ( $records ); 
    
$fp   =   fopen ( $file , " w " ); 
    
fputs ( $fp ,   $OUTPUT ); 
    
fclose ( $fp ); 
//  end else 
 
// 查询结果在数组 $records 中 

foreach  ( $records   as   $id => $row ) { 
    
if  ( $row [ ' category_id ' ==   $_REQUEST [ ' category_id ' ]) { 
        
//  被选择的目录显示粗体字 
         print   ' <B> ' . $row [ ' category_name ' ] . ' </B><BR> '
    } 
else  { 
        
//  其它目录显示用常规字体 
         print   $row [ ' category_name ' ] . ' <br> '
    } 
//  end foreach 


?>
关于作者
Ori Staub 是专注于研究基于WEB解决方案的中级系统分析员,开发者和顾问。可以通过电子邮件os@zucker-staub.com联系他。
原文地址:http://www.zend.com/zend/tut/tutorial-staub2.php
 

http://chatgpt.dhexx.cn/article/lYUCgekB.shtml

相关文章

数据库之查询缓存

查询缓存配置 查看当前的MySQL数据库是否支持查询缓存SHOW VARIABLES LIKE have_query_cache; 查看当前MySQL是否开启了查询缓存SHOW VARIABLES LIKE query_cache_type; 查看查询缓存的占用大小SHOW VARIABLES LIKE query_cache_size; 查看查询缓存的状态信息show status li…

数据库缓存

一、什么是数据库缓存 我们知道常见的数据库&#xff0c;比如oracle、mysql等&#xff0c;数据都是存放在磁盘中。虽然在数据库层也做了对应的缓存&#xff0c;但这种数据库层次的缓存一般针对的是查询内容&#xff0c;而且粒度也太小&#xff0c;一般只有表中数据没有变更的时…

【技术干货】缓存随谈系列之一:数据库缓存

本文作者: 乔锐杰 现担任上海驻云信息科技有限公司运维总监/架构师。曾任职过黑客讲师、java软件工程师/网站架构师、高级运维、阿里云架构师等职位。维护过上千台服务器,主导过众安保险、新华社等千万级上云架构。在云端运维、分布式集群架构等方面有着丰富的经验。 以…

内连接、外连接、全连接图示语法

外连接 外连接分为外左连接(left outer join)和外右连接(right outer join) left outer join 与 left join 等价&#xff0c; 一般写成left join right outer join 与 right join等价&#xff0c; 一般写成right join左连接&#xff1a;左侧交集部分 语法&#xff1a;…

MySQL 内连接、外连接、左连接、右连接、全连接

建表语句&#xff1a; CREATE TABLE a_table (a_id int(11) DEFAULT NULL,a_name varchar(10) DEFAULT NULL,a_part varchar(10) DEFAULT NULL ) ENGINEInnoDB DEFAULT CHARSETutf8CREATE TABLE b_table (b_id int(11) DEFAULT NULL,b_name varchar(10) DEFAULT NULL,b_part v…

SQL中的各种连接的区别总结(内连接,左连接,左外连接,右连接,右外连接,全连接,全外连接)

在数据库中建立两张表方便大家理解&#xff0c;teacher和student表(student表中的teacherid字段是对应teacher表中的ID&#xff0c;举个例子张三的老师就是李四&#xff0c;没有teacherid就是这个人暂时没有老师) INNER JOIN: 返回两个表的匹配得上的数据&#xff0c;不匹配不…

MYSQL语法:左连接、右连接、内连接、全外连接

文章目录 概念上手使用left join(左连接)rint join(右连接)inner join&#xff08;内连接&#xff0c;等同join&#xff09;full join&#xff08;全连接&#xff0c;等同full outer join&#xff09; 概念 left join&#xff08;左连接&#xff09;&#xff1a;返回包括左表中…

MySQL 的等值连接、交叉连接、左外连接 、右外连接、全外连接实例

1. 测试数据 测试数据如下所示&#xff0c;数据库脚本&#xff08;含数据&#xff09;在文章最后的附录中给出。 测试工具&#xff1a;MySQL8.0 &#xff0c; Navicat Premium。 首先是一个班级表&#xff1a;class&#xff0c;class表中的数据如下所示。 学生表: student&a…

数据库学习之MySQL (十六)—— SQL99 外连接 左外连接 右外连接 全外连接 交叉连接

文章目录 外连接 之 左外连接 与 右外连接为啥要用外连接全外连接总结 内连接 外连接交叉连接 外连接 之 左外连接 与 右外连接 我们先来看个之前的 女神男朋友的案例 传送&#xff1a;数据库学习之MySQL (十三&#xff09;——多表查询 SQL92 SQL99 连接种类划分 我们先考虑…

ORACLE的左右连接,全外连接

先上概念 oracle连接分为&#xff1a; 左外连接&#xff1a;左表不加限制&#xff0c;保留左表的数据&#xff0c;匹配右表&#xff0c;右表没有匹配到的行中的列显示为null。 右外连接&#xff1a;右表不加限制&#xff0c;保留右表的数据。匹配左表&#xff0c;左表没有匹配…

SQL的内连接、左连接、右连接、 交叉连接、全外连接

sql表连接分成 外连接 、 内连接 和 交叉连接。. 外连接包括三种,分别是左外连接、右外连接、全外连接。. 对应的sql关键字:LEFT/RIGHT/FULL OUTER JOIN,通常我们都省略OUTER关键字,写成LEFT/RIGHT/FULL JOIN。. 在左、右外连接中都会以一种表为基表&#xff0c;基表的所有行、…

Mysql中实现全外连接

MySql中多表查询只提供了内连接&#xff0c;左外连接与右外连接&#xff1a; table_reference {[INNER] JOIN | {LEFT|RIGHT} [OUTER] JOIN} table_reference ON conditional_expr 1】INNER JOIN ON内连接&#xff08;只写join时默认为内连接&#xff09; SELECT * FROM emp e…

mysql 全外连接报错的原因

mysql 不支持 直接写full outer join 或者 full join来表示全外连接但是可以用left right union right 代替。 全外连接图&#xff08;非原创图&#xff09; 下面的是全外连接例子&#xff1a; select * from table a A&#xff08;A为别名&#xff09;LEFT JOIN table b B …

Oracle:左连接、右连接、全外连接、(+)号详解

目录 Oracle 左连接、右连接、全外连接、&#xff08;&#xff09;号详解 1、左外连接&#xff08;LEFT OUTER JOIN/ LEFT JOIN&#xff09; 2、右外连接&#xff08;RIGHT OUTER JOIN/RIGHT JOIN&#xff09; 3、全外连接&#xff08;FULL OUTER JOIN/FULL JOIN&#xff0…

全外连接给你讲

你知道的越多&#xff0c;你不知道的就越多 先来看看标准SQL里面定义的外连接的三种类型&#xff1a; 左外连接右外连接全外连接 其中&#xff0c;左外连接和右外连接没有本质的区别&#xff0c;用作主表的表写在运算符左侧就是左外连接&#xff0c;卸载运算符右侧就是右外连接…

SegmentFault 技术周刊 Vol.30 - 学习 Python 来做一些神奇好玩的事情吧

前言 开始之前&#xff0c;我们先来看这样一个提问&#xff1a; python初学者&#xff0c;请教python学习路径 相信看完 X_AirDu 的回答我们已经对 Python 有了一个大概的了解。那接下来就让我们更深入的了解 Python 吧~ Python 入门 [零基础学Python]一些关于Python的事情 已经…

产品读书《金字塔原理》

PPT参考 1PPT参考2 其实我读这本书并不是把它当作一本读物来读&#xff0c;反倒觉得像是一本工具书&#xff0c;全书的内容可能干货不多&#xff0c;总结出来就是“金字塔”&#xff0c;倒没什么其他&#xff0c;再多也就是一些案例&#xff01;但是这个思想已经能让人俯首称赞…

转载-代码的马斯洛金字塔

从科技爱好者周刊&#xff08;第 156 期&#xff09;&#xff1a;显卡缺货与异业竞争看到的关于代码的马斯洛金字塔这种说法&#xff1b;搬运过来方便自己随时阅读&#xff1b; 原文是代码的马斯洛金字塔&#xff1b; 内容如下&#xff1a; As in Maslow’s pyramid, each laye…

需求挖掘:产品经理怎么基于项目做需求挖掘

零、需求分析的背景 日常工作中&#xff0c;我们常常面临别人提过来的需求要不要做&#xff0c;如何去挖掘新的需求、衡量需求的投入产出比等相应的场景&#xff0c;这些场景都涉及到我们对需求的分析和挖掘&#xff0c;也就意味着我们需要掌握足够多的认知和方法论去对指定的需…

如何思考总结,并如何写文档展示. 结构化思考, 金字塔思维

先看三张图: 术语: 交叉表, 是人分类能力提升的一个标志. (对问题思考可以分类到多个维度,并了解维度之间的层级关系,哪个更主要,哪个是次要) 该图的是最简单的整理表格. 进一步复杂的在数据分析上有专门的术语: 叫做交叉表 找不到了 1.上线前 道: 法(制度): 术…