【问题标题】:Improve many-to-many Query Performance with Pagination using Laravel 4.2使用 Laravel 4.2 通过分页提高多对多查询性能
【发布时间】:2021-06-26 15:01:47
【问题描述】:

我有一个看起来很简单的带分页的多对多关系查询。它工作正常,但缺点是需要时间。在 prod 服务器上,超过 20 秒。在我的开发环境中,13 秒。

代码如下:

$query = $this->excerpt->orderBy($sort, $order);
$excerpts = $query->with('source.authors')
            ->with('excerptType')
            ->with('tags')
            ->whereHas('tags', function($q) use ($tagId){
                $q->where('tag_id', $tagId);
            })
            ->paginate($this->paginateCount);

这两个查询耗时最长

select count(*) as aggregate
    from `excerpt`
    where (select count(*)
            from `tags`
            inner join `excerpt_tag`
                  on `tags`.`id` = `excerpt_tag`.`tag_id`
            where `excerpt_tag`.`excerpt_id` = `excerpt`.`id`
                 and `tag_id` = '655') >= 1

2.02 秒

select *
    from `excerpt`
    where (select count(*) from `tags`
            inner join `excerpt_tag`
                    on `tags`.`id` = `excerpt_tag`.`tag_id`
            where `excerpt_tag`.`excerpt_id` = `excerpt`.`id`
              and `tag_id` = '655') >= 1
    order by `created_at` desc limit 15 offset 0

2.02 秒

我正在考虑将其更改为带有内部联接的简单查询,例如:

select *
    from `excerpt`
    inner join excerpt_tag  on excerpt.id = excerpt_tag.excerpt_id
    inner join tags  on excerpt_tag.tag_id = tags.id
    where tags.id = 655
    limit 10  offset 0

但后来我失去了急切加载等的优势。

有没有人知道加快速度的最佳方法是什么?

【问题讨论】:

    标签: mysql laravel performance eloquent laravel-4.2


    【解决方案1】:

    改变

    ( SELECT COUNT(*) ... ) > 0
    

    EXISTS ( SELECT 1 ... )
    

    按照说明 here 在 many:many 表中获取索引提示。

    如果tag 只是一个短字符串,请不要为它们准备一张表 (tags)。相反,只需在excerpt_tag 中添加tag 并去掉tag_id

    没有ORDER BYLIMIT 有点毫无意义——你得到哪10 行将是不可预测的。

    【讨论】:

      【解决方案2】:

      我有一个解决方案,它带来了显着的改进,并且只添加了几行代码,并且只添加了 1 个或 2 个额外的 sql 查询。

      我决定先查询标签,找出连接了哪些摘录,然后使用whereIn查询摘录中的所有信息,因此希望仍然使用with功能和预加载。至少将查询数量降至最低。

      这是解决方案的代码:

          // workaround to make excerpt query faster
          $excerptsWithTag = $this->tag->with(['excerpts' => function($query) {
              $query->select('excerpt.id');
          }])->find($tagId,['tags.id']);
          // actual excrpt query
          $excerptIds = array_column($excerptsWithTag->excerpts()->get()->toArray(), 'id');
          $query = $this->excerpt->orderBy($sort, $order);
          $excerpts = $query->with([
                  'source.authors',
                  'excerptType',
                  'tags'
              ])
              ->whereIn('excerpt.id', $excerptIds)
              ->paginate($this->paginateCount);
      

      很可能有一种更有说服力的方法来解决这个问题,但这很有效,我很高兴。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-03
        • 1970-01-01
        • 2014-04-13
        • 2011-05-18
        • 1970-01-01
        • 1970-01-01
        • 2014-01-21
        • 1970-01-01
        相关资源
        最近更新 更多