从多个表中进行Sql高效查询

时间:2017-01-11 17:18:28

标签: mysql sql database database-design

我有两张表tbl_datatbl_user_data

tbl_data

结构

id (int) (primary)
names (varchar)
dept_id (int)
tbl_user_data

结构

id (int) (primary)
user_id (int)
names_id (int)

tbl_data.idtbl_user_data.names_id是外键

我的情况是我要从tbl_data中选择25个随机条目,这些条目之前没有提供给特定用户。所以我创建了一个tbl_user_data,它将存储user_idnames_id(来自已提供的tbl_data)。 我有点困惑,如何代表这个查询,还是有其他方法可以有效地做到这一点?

注意: tbl_data的参赛人数超过500万。

到目前为止,我已写过这篇文章,但似乎不对。

SELECT td.names, td.dept_id
FROM tbl_data AS td
LEFT JOIN tbl_user_data AS tud ON td.id = tud.names_id
WHERE tud.user_id !=2
ORDER BY RAND( ) LIMIT 25

3 个答案:

答案 0 :(得分:1)

两件事:

首先......您需要LEFT JOIN .... IS NULL模式来挑选尚未送达的商品。您需要在ON子句中提及用户ID才能使其正常工作。

SELECT td.names, td.dept_id
  FROM tbl_data AS td 
  LEFT JOIN tbl_user_data AS tud    ON td.id = tud.names_id
                                   AND tud.user_id = 2
 WHERE tud.id IS NULL
 ORDER BY RAND( ) LIMIT 25

其次,ORDER BY RAND() LIMIT ...在一张大桌子上表现糟糕。它必须选择整个表,然后对其进行排序,然后丢弃除了25个项目之外的所有项目。这是非常浪费的,永远不会表现得很好。

通过仅排序id值,然后使用它们来获取其他信息,您可以减少浪费。

这会获得25个随机ID值。

                 SELECT td.id
                   FROM tbl_data AS td 
                   LEFT JOIN tbl_user_data AS tud    ON td.id = tud.names_id
                                                    AND tud.user_id = 2
                  WHERE tud.id IS NULL
                  ORDER BY RAND( )
                  LIMIT 25

这会获取您的姓名和dept_id值。

  SELECT a.names, a.dept_id
    FROM tbl_data AS a
    JOIN (
                 SELECT td.id
                   FROM tbl_data AS td 
                   LEFT JOIN tbl_user_data AS tud    ON td.id = tud.names_id
                                                    AND tud.user_id = 2
                  WHERE tud.id IS NULL
                  ORDER BY RAND( )
                  LIMIT 25
         ) b ON a.id = b.id

但是,它仍然是浪费。您可能希望构建此tbl_data表的随机版本,然后按顺序使用它。你可以每天重新随机一次,就像这样。

 DROP TABLE tbl_data_random;
 INSERT INTO tbl_data_random FROM
 SELECT * 
   FROM tbl_data
  ORDER BY RAND()

这样你就不会一遍又一遍地进行排序,只是为了丢弃结果。相反,你偶尔随机化一次。

答案 1 :(得分:0)

在names_id和user_id上创建索引。为什么是user_id varchar? 如果需要varchar并且varchar非常长,请在user_id上创建部分索引。 您可以使用EXPLAIN来查看使用查询的索引。

答案 2 :(得分:0)

由于您没有从tbl_user_data中选择任何内容,因此您可以使用exists代替:

SELECT td.names, td.dept_id
FROM tbl_data AS td
where exists (
    select 1
    from tbl_user_data AS tud 
    where td.id = tud.names_id
    and tud.user_id !=2
)
ORDER BY RAND( ) LIMIT 25

tbl_data(id)和tbl_user_data(names_id,user_id)的索引会有所帮助。