【问题标题】:Querying for friends and friends of friends optimization好友查询好友优化
【发布时间】:2015-06-02 21:43:35
【问题描述】:

我需要运行查询以获取数据透视表上的所有朋友 ID 及其朋友的 ID。

该表有两列(与此问题相关),请求者 ID 和接受者 ID。

要获取用户的所有朋友,我必须获取 accepter_id == currentUserIdrequester_id == currentUserId 的所有行,因为当前用户可以是请求者或接受者。

问题:

要获取朋友 ID 的所有朋友,我需要对每个当前用户朋友的 ID 运行查询(accepter_id == currentUsersFriendId AND requester_id == currentUsersFriendId)。

很多时候查询量超过200(取决于当前用户的好友数量)。当我对它进行基准测试时,我总是在 2.2 到 2.7 秒左右完成获得朋友和朋友的朋友。显然这需要很长时间。

问题:

我可以做些什么来减少完成此查询所需的时间?

注意:我使用的是 Laravel 的 Eloquent ORM。

更新

对于表格,我使用的是 Laravel Schema builder(而且我不是 sql 专家)。因此,我可以向您展示的是 create table 语句的 php 代码表示。这是 Schema 构建器的 Laravel 文档:http://laravel.com/docs/4.2/schema。希望这能有所帮助?

Schema::create('friends', function (Blueprint $table)
    {
        $table->increments('id');
        $table->integer('requester_id', false, true);
        $table->integer('accepter_id', false, true);
        $table->tinyInteger('status');

        $table->unique(['requester_id', 'accepter_id']);

        $table->timestamps();
        $table->softDeletes();
    });

这里是拉朋友的选择语句。请注意,我正在对where requester_id = userIdwhere accepter_id = userId 运行单独的查询。无法弄清楚如何将两者结合在一起,所以我运行了单独的查询并将它们结合起来。

select `requester_id` from `friends` where `accepter_id` = ? and `status` = ?
select `accepter_id` from `friends` where `requester_id` = ? and `status` = ?

【问题讨论】:

  • 你对这些列有索引吗?
  • 我有一个用于请求者和接受者 ID 的复合唯一键。
  • 我会尝试在这两列上放置一个索引; 2.2到2.7是直接在DB里面执行查询吧?
  • 唯一的键是索引,我相信?我不确定你的第二个问题是什么意思。你的意思是我直接与数据库通信,而不是使用数据库查询的 php 代码表示?
  • SHOW CREATE TABLE 并向我们展示您正在使用的SELECT

标签: php mysql algorithm laravel optimization


【解决方案1】:

您需要两个单独的复合索引:

INDEX(requester_id, status, accepter_id)
INDEX(accepter_id, status, requester_id)

那么这个UNION会跑的快很多:

( select `requester_id` from `friends` where `accepter_id` = ? and `status` = ? )
UNION ALL
( select `accepter_id` from `friends` where `requester_id` = ? and `status` = ? )

如果从这两个 SELECT 中返回重复项,并且您需要对列表进行重复数据删除,则使用 UNION DISTINCT 而不是 UNION ALL

【讨论】:

  • 说 UNIQUE 而不是简单的 INDEX 没有任何好处。另一方面,如果这可行,为什么要使用idPRIMARY INDEX(requerster_id, accepter_id)
  • 在 Laravel 框架中有约定,并且有一个 id 主键使事情变得更简单。无论如何,我正在实施您的解决方案,我会尽快回复您
  • 抱歉,花了这么长时间,我在搞砸了一些之后做了一些基准测试。我将平均时间从 2.4 秒降至 1.4 秒(所用时间的 62%)。但我更进一步,完全放弃了 ORM 并使用了 PDO。这将其平均下降到 0.6 秒,与原始查询相比,这需要四分之一的时间。我不太确定第二个索引对查询有什么影响,尽管我没有为它们制作单独的测试用例。
  • 啊,第 3 方软件阻碍的另一个例子——尤其是在性能方面。 ORM 和 PDO 哪个更容易编写代码?
  • 当然是ORM(更简单),这是我使用它的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-24
  • 2012-07-30
  • 1970-01-01
相关资源
最近更新 更多