【问题标题】:how to cache based on many parameters如何根据许多参数进行缓存
【发布时间】:2009-09-01 14:50:19
【问题描述】:

我正在开发一个搜索应用程序,该应用程序使用具有 16 个过滤器选项的表单,这些选项是 1(​​已选择)或 0(未选择)。使用 GET 请求通过 AJAX 检索 JSON 格式的结果。

查询字符串如下所示:

filter_1=0&filter_2=1 ...省略... &filter_16=1&page=20

每个搜索结果至少有 2 个页面可供用户浏览。

我的问题是:如何根据输入参数缓存搜索结果?我的第一个想法是 md5 请求参数,然后使用哈希作为文件名编写缓存文件。

每次收到新请求时,我都会搜索缓存文件,如果存在,则使用该文件中的数据,而不是查询数据库并将行转换为 json 结果。

但这似乎不是一个好主意,因为搜索选项很多。会有很多缓存文件(16 * 16 ???),并且由于该应用程序仅由少数用户使用,我怀疑所有可能的组合都会被缓存。每个结果都包含 X 页,因此每个页面都是它自己的缓存文件 (16 * 16 * X)。

对于这样的应用程序来说,什么是好的缓存策略?是否真的可以实现缓存?

【问题讨论】:

    标签: php caching


    【解决方案1】:

    由于您的所有搜索参数都是可以为 0 或 1 的标志,因此您可以考虑使用位掩码。

    您的每个过滤器都代表一个 2 的幂的值:

    $filter_1 = 1;
    $filter_2 = 2;
    $filter_3 = 4;
    ...
    $filter_8 = 256;
    ...
    $filter_16 = 65536;
    

    通过使用 PHP 的bitwise operators,您可以轻松地将所有 16 个过滤器值存储在一个整数中。例如,值“257”只能使用 filter_1 和 filter_8 的组合来达到。如果用户选择了 filter_1 和 filter_8,您可以通过以下方式确定位掩码:

    $bitmask = $filter_1 | $filter_8  //gives 257
    

    通过代表所有过滤器状态的唯一位掩码,您也可以简单地将其用作缓存键,而无需昂贵的 md5 操作。因此,在这种情况下,您需要将名为“257”的文件保存到缓存中。

    此技术还为您提供了一个简单的工具来使缓存无效,因为您可以检查新记录和更新记录以确定它们匹配哪些过滤器,并删除名称中设置了该“位”的任何文件,即。 if ( ((int)$filename) & $filter == $filter) unlink($filename);。如果您的表频繁写入,这可能会导致扫描缓存时出现一些性能问题,但对于读取繁重的应用程序来说,这是一种不错的技术。

    这是我在处理位或标志时喜欢使用的一种方法。但是,如果您真的需要这样的缓存,您应该仔细考虑。如果您只有几个系统用户,您真的会遇到基于几个搜索查询的性能问题吗?同样,MySQL 具有内置的查询缓存,在高读取应用程序上表现得非常好。如果您的结果页面生成例程成本很高,那么缓存输出片段肯定是有益的,但如果您在这里只为少数用户谈论微秒级的性能,那可能就不值得了。

    【讨论】:

      【解决方案2】:

      为什么需要缓存?

      如果该应用仅由少数用户使用,则实际上可能不需要缓存。

      【讨论】:

        【解决方案3】:

        鉴于您描述的要求(少量用户),在我看来缓存所有组合似乎是合理的。当然,除非缓存是有意义的。一个典型的查询需要多长时间?既然你说这个应用程序只会被几个人使用,那还值得缓存吗?我非常粗略的估计是,如果在这种情况下查询不会花费几秒钟,请不要担心缓存。如果不到一秒,并且您真的不想让应用程序响应超级快,则不需要缓存。

        否则,我会说(再次考虑到少量用户)缓存所有组合是可以的。即使使用的数量非常多,最多也有 65536 个,许多现代操作系统可以轻松处理目录中的数千个文件(以防您打算缓存到文件中)。但无论如何,限制缓存中的项目数量并定期清除旧项目是合理的。另外,我不会使用 MD5,我只会将过滤器中的零和一连接起来作为缓存键(例如 0101100010010100)。

        【讨论】:

          【解决方案4】:

          首先确认你确实需要一个缓存(就像托比建议的那样)。

          然后,考虑一下信息需要多新鲜 - 您需要清除旧值。您可能需要为此使用预先存在的解决方案,例如 memcached

          $key = calc_key();
          
          $result = $memcache->get($key);
          
          if (!$result) {
            $result = get_data_from_db();
            /* cache result for 3600 seconds == 1 hour */
            $memcache->set($key, $result, 0, 3600);
          }
          
          /* use $result */
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-03-20
            • 1970-01-01
            • 2018-03-11
            • 1970-01-01
            相关资源
            最近更新 更多