Laravel Eloquent 缓存分页聚合计数结果

标签 laravel eloquent laravel-5.6 laravel-cache

是否可以缓存分页查询的计数结果?

select count(*) as aggregate from table_name

我的表有 2 000 000+ 个数据,每次计算这个计数需要大约 300 毫秒。将此结果缓存 1 小时就足够了,谢谢!

最佳答案

我需要扩展 Illuminate\Database\Eloquent\ModelIlluminate\Database\Eloquent\Builder

我的扩展 Builder 类

<?php

namespace App\Laravel\Database\Eloquent;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Cache;

/**
 * @mixin \Illuminate\Database\Query\Builder
 */
class CachedBuilder extends Builder
{
    const CACHE_THRESHOLD = 10000;
    const CACHE_DURATION = 60;
    const CACHE_KEY_PREFIX = 'pagination_';

    /**
     * Paginate the given query.
     *
     * @param  int  $perPage
     * @param  array  $columns
     * @param  string  $pageName
     * @param  int|null  $page
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     *
     * @throws \InvalidArgumentException
     */
    public function paginate($perPage = null, $columns = ['*'], $pageName = 'page', $page = null)
    {
        $page = $page ?: Paginator::resolveCurrentPage($pageName);

        $perPage = $perPage ?: $this->model->getPerPage();

        $key = self::CACHE_KEY_PREFIX . '_' . $this->getModel()->getTable();
        $key .= '_'.md5($this->query->toSql().join('/', $this->query->getBindings()));

        $total = Cache::get($key);
        if(!$total) {
            $total = $this->toBase()->getCountForPagination();
            if($total > self::CACHE_THRESHOLD) {
                Cache::put($key, $total, self::CACHE_DURATION);
            }
        }

        $results = $total ? $this->forPage($page, $perPage)->get($columns)
                    : $this->model->newCollection();

        return $this->paginator($results, $total, $perPage, $page, [
            'path' => Paginator::resolveCurrentPath(),
            'pageName' => $pageName,
        ]);
    }

}

我的扩展模型类

<?php

namespace App\Laravel\Database\Eloquent;

use Illuminate\Database\Eloquent\Model;

abstract class CachedModel extends Model
{

    /**
     * @param \Illuminate\Database\Query\Builder $query
     * @return CachedBuilder|\Illuminate\Database\Eloquent\Builder|static
     */
    public function newEloquentBuilder($query)
    {
        return new CachedBuilder($query);
    }
}

现在我只需要使用这个新的 CachedModel 类扩展我的任何模型即可应用总计数结果的缓存。

关于Laravel Eloquent 缓存分页聚合计数结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51174870/

相关文章:

mysql - Laravel 5.2 中的多表搜索查询

javascript - vuejs 和 laravel 中的路由不支持 post 方法

php - Laravel 5.6 - 如何获取房间交易的最后 X 位客人姓名?

php - 无法将 Laravel 应用程序部署到 Heroku - symfony/polyfill-ctype v1.24.0 需要 php >=7.1

php - 在 Laravel 的数据库中设置值时如何显示复选框已选中

Laravel:有些东西正在改变方法,它是什么?

mysql - 在 Laravel 5.6 中注册时出错

laravel - 如何提高电子邮件的稳健性? [邮件枪,laravel]

php - 有没有办法将原始查询映射到模型

Laravel 可终止中间件和后中间件之间的区别