0

我在一所学校工作,一直在寻找一种方法来加快和改进我们的一些数据库功能的工作方式。我们有一个 PHP 格式化类,现在数据库变得越来越大并且一些查询更长,它似乎正在减慢速度。

该类执行诸如获取外键并在查找表中查找该键的值之类的操作。

例如,学生类将使用格式化类: courseID = 114 并且每次使用 mysql 查询都会查找 studentID 以返回 Biology 和 John Doe。

我的问题是有些类会生成一个对象数组,例如 500 个学生对象的数组,每个学生类都访问这个格式化程序类,因此运行几个查询。

我在想这会减慢速度

最坏的情况是格式化程序类中的 500 个学生对象 x 10 次查找,这意味着执行了 5000 个查询。

我想知道处理这个问题的最佳方法。

我是否将所有查找数据预加载到该格式化程序类中的数组中?

使该格式化类成为一个实例(单例),以便在最坏的情况下,一个生成整个类数组的主类使用该唯一类。

将所有已解析的查找数据存储在一个数组中是否更好(缓存问题?)

有些类现在有太多查询,它们不再起作用。

在下面编辑 2013 年 8 月 23 日

添加更多信息。

我并不真正关心单个查找,那些在速度方面没有问题。例如老师查找一个学生的信息。让格式化程序类运行 10 个查询是没有问题的。

生成大量其他对象的类,例如老师要求查看所有学生,其中有 500 个对象是问题所在。

我有几个这样的类,为所有这些类创建一个 Join 可能是最快的,但正如有人指出的那样做很多工作。

编辑 2014 年 1 月 30 日想感谢 Lorenz Meyer 对我的速度问题的良好开端,一直在研究一些建议!!!!

我还有一个相关的问题。

对于更简单的查找,例如存储 50 对值的值,例如教师 ID 和相应的教师姓名。

选项 1:在某些情况下,我在某些表中添加了一个字段,并让脚本使用该值预先填充这些字段,例如该行中 teacherIds 的教师姓名。在运行时,该字段已经有一个值,我在一些巨大的脚本中这样做了,它大大减少了查询量。

使用 Cron 运行脚本,这是一个不错的解决方案,但我可以看到它成为一个问题,仅将用于渲染数据的字段添加到这么多表

选项 2:我一直在考虑使用 $_Session 来存储该对数据。用户登录后,一组teacherIds 和全名会在 $_Session 数据中填充一个数组。以前使用查找来查找教师姓名的任何班级都可以使用 $_Session 数组并改用它,并使用后备来查询查找表以防万一。我没有很多并发用户,最多 30 个,所以这似乎不会造成太大的负担,并且会将其限制在一些较小的查找表中。

人们对这两个选项有何看法,尤其是选项 2。

4

1 回答 1

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 次是没有意义的。您应该重写代码,以便查询获取所有数据,然后为记录集的每一行格式化数据。

于 2013-08-22T12:47:25.530 回答