我在一所学校工作,一直在寻找一种方法来加快和改进我们的一些数据库功能的工作方式。 我们有一个PHP格式化的类,由于数据库变得越来越大,一些查询越来越长,似乎正在减慢速度。
该类执行诸如获取外键并在查找表中查找该键的值的操作。
例如,学生班将使用格式化类: courseID = 114并且每次使用mysql查询时都会查找studentID以返回Biology和John Doe。
我的问题是有些类生成一个对象数组,例如500个学生对象的数组,每个学生类都访问这个格式化程序类,从而运行多个查询。
我认为这会让事情变得缓慢
最坏的情况 500个学生对象x格式化程序类中的10个查找,这意味着执行了5000个查询。
我想知道解决这个问题的最佳方法。
我是否将所有查找数据预加载到一个格式化程序类中?
使该格式化的类成为一个实例(单例),以便在最坏的情况下,一个生成整个类数组的主类使用该类而且只使用类。
将已解析的所有查找数据存储在一个数组中是否更好(缓存问题?)
有些课程现在有很多查询,不再有效。
编辑下面的2013年8月23日
添加更多信息。
我并不真正关心单个查找,那些速度没有问题。比如老师查找一个学生的信息。让格式化程序类运行10个查询是没有问题的。
生成大量其他对象列表的类,例如教师要求查看所有学生,其中有500个对象是问题。
我有几种类型的类,为所有类创建一个加入可能是最快的,但有人指出了很多工作。
编辑2014年1月30日 想要感谢Lorenz Meyer在速度问题上的良好开端,一直在努力提出一些建议!!!!
我还有一个相关的问题。
对于更简单的查找,请说存储50对值的值,例如teacherIds和相应的教师名称。
选项1: 在某些情况下,我在某些表中添加了一个字段,并且脚本会使用该值预先填充这些字段,例如该行中teacherIds的教师名称。在运行时,该字段已经有一个值,我在一些巨大的脚本中做了这个,它大大减少了查询量。
使用Cron来运行脚本,这是一个很好的解决方案但是我可以看到它只是为了将渲染数据添加到这么多表中而成为一个问题
选项2: 我一直在考虑使用$ _Session存储该对数据。用户登录后,一个teacherIds和Full Names数组会在$ _Session数据中填充一个数组。以前使用查找来查找教师姓名的任何类都可以使用$ _Session数组并使用该数组,并使用后备查询查询表以防万一。 我没有很多并发用户,最多30个,所以看起来这不会非常费力,而且会将它限制在一些较小的查找表中。
人们对这两个选项有何看法,尤其是选项2。
答案 0 :(得分:2)
我看到了三种解决方案,我将它们从最简单到最重,但最有效。
此解决方案是在此函数中包含一个静态变量,并将其用作学生和类的临时存储。这样可以减少查询次数,因为您只查询每个学生一次,每个课程只查询一次。
像这样的东西
function format($studentid, $classid){
static $students = array();
static $classes = array();
if !isset($students[$studentid]) $students[$studentid] db_lookup($studentid);
if !isset($classes[$classid]) $classes[$classid] db_lookup($classid);
$student_name = $students[$studentid];
$class_name = $classes[$studentid];
(...)
而不是
function format($studentid, $classid){
$student_name = db_lookup($studentid);
$class_name = db_lookup($classid);
(...)
此解决方案非常易于实现,但它仅为一个请求缓存结果,例如,如果您显示的表格包含多次相同的课程。
对于请求之间的缓存,您需要使用缓存解决方案,例如PEAR包Cache_Lite。它允许使用固定值(例如db_lookup($studentid=123)
)缓存函数调用的结果,并将结果存储在缓存中。 Cache_Lite实现了内存缓存,文件缓存和数据库缓存。我将它与memcache一起使用,效果很好。
此解决方案需要更多工作,它将使用磁盘空间或内存。
最有效的解决方案,但需要付出最大努力的是重构代码。每次查询500次数据库一行是没有意义的。您应该重写代码,以便查询获取所有数据,然后格式化记录集的每一行的数据。