从表中选择其他表中最有效的方式

时间:2015-03-21 19:58:36

标签: mysql sequelpro

我的mySQL数据库中有一个ID号列表作为一个表;我有第二个包含From_IDTo_IDFrequency列的表格。

我希望制作一个与第二个表格具有相同结构的第三个表格,但只包含那些'来自'和'到' ID位于第一个表中。

第一个表有大约80k行,第二个表有大约45万行。这花了很长时间才使得这个过程似乎没有在合理的时间内结束(不少于一天)。

我目前的查询如下:

CREATE table3 AS (SELECT * FROM table2 
                  WHERE from_id IN (SELECT id FROM table1) 
                  AND to_id IN (SELECT id FROM table1);

如果有人能告诉我更有效的方法,我会非常感激!

2 个答案:

答案 0 :(得分:2)

首先,使用exists而不是in

SELECT t2.*
FROM table2 t2
WHERE EXISTS (SELECT 1 FROM table1 t1 WHERE t1.id = t2.from_id) AND
      EXISTS (SELECT 1 FROM table1 t1 WHERE t1.id = t2.to_id);

然后确保您在table1(id)上有索引。后者非常重要。

作为注释:您可以通过将limit 100,然后limit 1000等添加到查询中来在用户界面中测试查询。这将让您了解数据增长时的性能。

答案 1 :(得分:1)

  

我想创建一个与第二个表结构相同的第三个表,但只有那些'from'和'to'ID在第一个表中的行。

这被称为"denormalization"虽然有正当理由这样做,但它不被认为是良好的数据库设计,应该避免使用。

大概你想这样做是因为你的查询太慢了。那么让我们来看看你的问题。

SELECT *
FROM  table2 
WHERE from_id IN (SELECT id FROM table1) 
  AND to_id   IN (SELECT id FROM table1)

如果MySQL必须对table1进行全表扫描,这可能会很慢,但它似乎很聪明,可以识别它可以使用索引。

mysql> explain SELECT * FROM table2                    WHERE from_id IN (SELECT id FROM table1)                    AND to_id IN (SELECT id FROM table1);
+----+-------------+--------+--------+---------------+---------+---------+---------------------+------+-------------+
| id | select_type | table  | type   | possible_keys | key     | key_len | ref                 | rows | Extra       |
+----+-------------+--------+--------+---------------+---------+---------+---------------------+------+-------------+
|  1 | SIMPLE      | table2 | ALL    | NULL          | NULL    | NULL    | NULL                |    4 | Using where |
|  1 | SIMPLE      | table1 | eq_ref | PRIMARY       | PRIMARY | 4       | test.table2.from_id |    1 | Using index |
|  1 | SIMPLE      | table1 | eq_ref | PRIMARY       | PRIMARY | 4       | test.table2.to_id   |    1 | Using index |
+----+-------------+--------+--------+---------------+---------+---------+---------------------+------+-------------+
3 rows in set (0.00 sec)

我认为可以通过明确询问子查询中的确切ID来更好地表达。

SELECT t2.*
FROM   table2 t2
WHERE  (SELECT 1 FROM table1 t1 WHERE t1.id = t2.from_id)
  AND  (SELECT 1 FROM table1 t1 WHERE t1.id = t2.to_id)

mysql> explain SELECT t2.*     FROM   table2 t2     WHERE  (SELECT 1 FROM table1 t1 WHERE t1.id = t2.from_id)       AND  (SELECT 1 FROM table1 t1 WHERE t1.id = t2.to_id);
+----+--------------------+-------+--------+---------------+---------+---------+-----------------+------+-------------+
| id | select_type        | table | type   | possible_keys | key     | key_len | ref             | rows | Extra       |
+----+--------------------+-------+--------+---------------+---------+---------+-----------------+------+-------------+
|  1 | PRIMARY            | t2    | ALL    | NULL          | NULL    | NULL    | NULL            |    4 | Using where |
|  3 | DEPENDENT SUBQUERY | t1    | eq_ref | PRIMARY       | PRIMARY | 4       | test.t2.to_id   |    1 | Using index |
|  2 | DEPENDENT SUBQUERY | t1    | eq_ref | PRIMARY       | PRIMARY | 4       | test.t2.from_id |    1 | Using index |
+----+--------------------+-------+--------+---------------+---------+---------+-----------------+------+-------------+
3 rows in set (0.00 sec)

很难说哪一个会更快,我没有你的数据集。只要table2.from_id,table2.to_id和t1.id被索引,并且它们应该只要它们被正确地声明为外键和主键,你应该没问题。

如果仍然不够快,我会建议您create a view或临时表或query cache,而不是非规范化。这些可以有效地缓存查询而无需非规范化。您选择哪种方式取决于数据更新的频率以及应用程序对更改的敏感程度。