如何使用大型IN子句优化此SQL查询?

时间:2013-01-04 01:01:29

标签: mysql sql

我有一个相当复杂的操作,我只想用一个SQL查询来执行,但我不确定这是否比将其分解为n个查询更好或更不优。基本上,我有一个名为“Users”的表,其中包含用户ID及其关联的fb_ids(id为pk,fb_id可以为null)。

+-----------------+
| id | .. | fb_id |
|====|====|=======|
| 0  | .. | 12345 |
| 1  | .. | 31415 |
| .. | .. |  ..   |
+-----------------+

我还有另一个名为“Friends”的表,它代表两个用户之间的朋友关系。这使用了他们的id(而不是他们的fb_ids),应该是双向关系。

+----------------+
| id | friend_id |
|====|===========|
| 0  |     1     |
| 1  |     0     |
| .. |    ..     |
+----------------+
// user 0 and user 1 are friends

所以这就是问题: 我们得到一个特定用户的id(“my_id”)和该用户的Facebook好友的数组(一个名为fb_array的fb_ids数组)。我们想要更新Friends表,以便将Facebook友谊作为我们用户之间的有效友谊。值得注意的是,并非所有的Facebook好友都会在我们的数据库中拥有一个帐户,所以应该忽略这些朋友。每次用户登录时都会调用此查询,以便在Facebook上添加任何新朋友时可以更新我们的数据。这是我写的查询:

INSERT INTO Friends (id, friend_id)
SELECT "my_id", id FROM Users WHERE id IN
  (SELECT id FROM Users WHERE fb_id IN fb_array)
AND id NOT IN
  (SELECT friend_id FROM Friends WHERE id = "my_id")

第一个IN子句的要点是获取所有也是你的Facebook好友的用户的子集,这是我担心的主要部分。因为fb_ids是作为数组给出的,所以我必须将所有id解析成一个由逗号分隔的巨大字符串,这些字符串组成“fb_array”。我担心这个IN子句有这么大的字符串的效率(用户可能在Facebook上有成百上千的朋友)。您能想出更好的方法来编写这样的查询吗?

同样值得注意的是,这个查询并没有保持朋友关系的双重性质,但这并不是我所担心的(为此扩展它将是微不足道的。)

2 个答案:

答案 0 :(得分:1)

如果我没有弄错的话,如果您对组合UNIQUE(id, friend_id)约束,则可以简化您的查询:

INSERT IGNORE INTO Friends 
  (id, friend_id)
SELECT "my_id", id 
FROM Users 
WHERE fb_id IN fb_array ;

您应该在User (fb_id, id)上设置索引并测试效率。如果数组中的itmes数量太大(超过几千),则可能必须拆分数组并多次运行查询。配置文件包含您的数据和设置。

答案 1 :(得分:1)

取决于以下列是否可为空(值可以是NULL):

  • USERS.id
  • FRIENDS.friend_id

可为空:

SELECT DISTINCT
       "my_id", u.id 
  FROM Users u
 WHERE u.fb_id IN fb_array
   AND u.id NOT IN (SELECT f.friend_id 
                      FROM FRIENDS f
                     WHERE f.id = "my_id")

不可为空:

   SELECT "my_id", u.id 
     FROM Users u
LEFT JOIN FRIENDS f ON f.friend_id = u.id
                   AND f.id = "my_id"
    WHERE u.fb_id IN fb_array
      AND f.fried_id IS NULL

欲了解更多信息:

说出数组中值的数量

上述两篇文章中的测试包含100万行,有10,000个不同的值。