1

我有一张谁是谁的朋友的表格,它有以下简单内容:

user_id1 | user_id2 | <some other data>

具有非唯一索引:index_on_user1index_on_user2

两列都包含相同类型的数据,友谊总是双向的。

1 | 2

= user1是 user 的朋友,2user2是 user 的朋友1

我想要的是获得一个查询,该查询将始终为我提供我提供的任何 user_id 的朋友列表。

到目前为止,我一直在使用

SELECT if(`user_id1` = $user_id, `user_id2`, `user_id1`) as friend
FROM `Friends`
WHERE `user_id1` = $user_id OR `user_id2` = $user_id

但我有更多查询,我想在其中获取此信息作为子查询,并将包含此查询的视图作为子查询。所以我一直在寻找一种方法来抽象这个,有一些简单的选择,总能得到我朋友的 id,而不会有那个if声明的麻烦。

我对工会有这个想法:

CREATE OR REPLACE VIEW get_friend AS 
SELECT 
    `user_id1` as subject,
    `user_id2` as friend,
    FROM `Friends` 
    USE INDEX (`index_on_user1`)
UNION
SELECT
    `user_id2` as subject,
    `user_id1` as friend,
    FROM `Friends` 
    USE INDEX (`index_on_user2`)

使用简单SELECT friend FROM get_friend WHERE subject = $user_id来获得结果,并且它有效。

但是explain select...说它不使用索引,即使有提示。

我怎样才能让它使用这些索引?甚至可能吗?还有其他一些解决方案吗?

4

2 回答 2

2

您需要在 UNION 语句的各个查询中包含 WHERE 子句才能使用索引。本质上,您对视图的查询正在执行此操作

SELECT subject, friend FROM
(SELECT 
    `user_id1` as subject,
    `user_id2` as friend,
    FROM `Friends` 
    USE INDEX (`index_on_user1`)
UNION
SELECT
    `user_id2` as subject,
    `user_id1` as friend,
    FROM `Friends` 
    USE INDEX (`index_on_user2`)
) WHERE friend = <some number>

尝试对 UNION 运行 EXPLAIN 查询并填写适当的 where 子句,您应该会看到正在使用索引。

于 2013-07-09T01:29:09.637 回答
1

您不能在一个视图上使用不同的索引。为了获得你想要的性能,你必须在你需要的地方编写原始 SQL(比如你的联合)。

更好的解决方案是存储关系的两个方向。这是一些非规范化的数据,但不多。这样做会使您的查询变得简单并且执行良好。

为避免保存“其他数据”,您可以创建一个仅包含 id 的新表。使用触发器填充它并使其与主表对齐。

于 2013-07-09T01:38:23.047 回答