0

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

我想创建第三个表,其结构与第二个表相同,但只有第一个表中的“来自”和“到”ID 的行。

第一个表有 ≈ 80k 行,第二个有 ≈ 4500 万行。花费的时间太长,以至于该过程似乎无法在合理的时间内(不少于一天)结束。

我目前的查询如下:

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

如果有人能告诉我一个更有效的方法来解决这个问题,我将不胜感激!

4

2 回答 2

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, thenlimit 1000等放在查询上来测试查询。这将让您看到随着数据增长的性能如何。

于 2015-03-21T20:02:56.150 回答
1

我想创建第三个表,其结构与第二个表相同,但只有第一个表中的“来自”和“到”ID 的行。

这被称为“非规范化”,虽然这样做有正当理由,但它不被认为是好的数据库设计,应该避免。

大概你想这样做是因为你的查询太慢了。因此,让我们看看您的查询。

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 被索引,只要它们被正确声明为外键和主键,你应该没问题。

如果它仍然不够快,而不是非规范化,我建议您创建一个视图或临时表或查询缓存。这些可以有效地缓存查询,而不必进行非规范化。您选择哪一种取决于您的数据更新频率以及您的应用程序对更改的敏感程度。

于 2015-03-21T20:15:30.373 回答