2015-03-21 3 views
0

У меня есть список идентификационных номеров как одна таблица в моей базе данных mySQL; У меня есть вторая таблица, которая содержит From_ID, To_ID и Frequency столбцы.Выберите из таблицы, где в другой таблице наиболее эффективный способ

Я хочу сделать третью таблицу с той же структурой, что и вторая, но только с теми строками, для которых идентификаторы «от» и «до» находятся в первой таблице.

Первая таблица имеет ≈ 80 тыс. Строк, а вторая - ≈ 45 млн. Это длится так долго, что процесс, похоже, не закончится в разумные сроки (не менее одного дня).

Мой текущий запрос выглядит следующим образом:

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

Если кто-нибудь может сказать мне более эффективный способ пойти об этом, я очень ценю это!

ответ

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 и т. Д. На запрос. Это позволит вам увидеть, что такое производительность по мере роста данных.

+0

Это сработало отлично - спасибо! Прошел от 24 до 175 секунд. –

+0

99,8% улучшение;) На самом деле, индекс получает кредит на это. –

1

Я хочу сделать третью таблицу с той же структурой, что и вторая, но только с теми строками, для которых идентификаторы «от» и «до» находятся в первой таблице.

Это называется "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) 

Я думаю, что это может быть выражено лучше, явно запрашивая точный идентификатор в дополнительном запросе.

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. Они могут эффективно кэшировать запрос без необходимости денормализации. Выбор, который вы выбираете, зависит от того, насколько часто ваши данные обновляются и насколько чувствительны ваши приложения к изменениям.

+0

Спасибо за такой подробный ответ.Я собираюсь с денормализацией, потому что: a) мне нужно много работать с подмножеством b) мне нужно экспортировать подмножество и c) данные не будут меняться ... на мой взгляд, b) на самом деле не является действительная причина, но (я думаю?) a) есть. Также Sequel Pro не позволяет создавать представления ... –

Смежные вопросы