简体   繁体   中英

having pairs of friends in table, how to make a view that would abstract getting list of user's friends?

I have a table of who's friend with who, it has following simple:

user_id1 | user_id2 | <some other data>

with non-unique indexes: index_on_user1 and index_on_user2

Both columns contain same type of data, the friendship always goes both ways.

1 | 2

= user 1 is friend with user 2 , and user 2 is friend with user 1 .

What I want is to get a query that will consistently give me list of friends of whatever user_id I provide.

Up till now, I've been using

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

but I've got more queries, where I'd like to get this info as a sub query, and make views containing this query as a sub-query. So I was looking for a way to abstract this, to have some simple select that would always get me friend's id, without having that hassle with that if statement.

I've got this idea with union:

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`)

using simple SELECT friend FROM get_friend WHERE subject = $user_id to get the result, and it works.

But explain select... says it doesn't use index, not even with the hint.

How can I make it use those indexes? Is it even possible? Are there some other solutions?

You need to have a WHERE clause in the individual queries in the UNION statements in order to use the index. Essentially your query to the view is doing this

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>

Try running the EXPLAIN query against the UNION with the appropriate where clauses filled in and you should see that the indices are being used.

You can't use different indexes on the one view. To get the performance you want you must code the raw SQL (like your union) where you need it.

A much better solution would be to store both directions of the relationship. It's some denormalhzed data, but not much. Doing this would make your queries simple and perform well.

To avoid saving the "other data", you could create a new table with just the ids. Use triggers to populate it and keep it aligned with the main table.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM