НЕ В подзапросе против ВКЛ! = Операция - PullRequest
0 голосов
/ 29 октября 2018

У меня есть две таблицы с именами ny_clean (3454602 записей) и pickup_0_ids_temp_table (2739268 записей), у которых есть столбец id CHAR (11), который является первичным ключом, и поверх него индекс BTREE (MySQL 5.7).

Столбец "id" в pickup_0_ids_temp_table является подмножеством ny_clean, и я хочу получить результат ny_clean без значений идентификатора из pickup_0_ids_temp_table.

Вариант 1:

EXPLAIN
SELECT *
FROM pickup_0_ids_temp_table as t
JOIN ny_clean as n
ON n.id != t.id;
+----+-------------+----------+------------+-------+---------------+-------------------+---------+------+---------+----------+-----------------------------------------------------------------+
| id | select_type | table    | partitions | type  | possible_keys | key               | key_len | ref  | rows    | filtered | Extra                                                           |
+----+-------------+----------+------------+-------+---------------+-------------------+---------+------+---------+----------+-----------------------------------------------------------------+
|  1 | SIMPLE      | t        | NULL       | index | NULL          | PRIMARY           | 11      | NULL | 2734512 |   100.00 | Using index                                                     |
|  1 | SIMPLE      | ny_clean | NULL       | index | NULL          | btree_pk_ny_clean | 11      | NULL | 3445904 |    90.00 | Using where; Using index; Using join buffer (Block Nested Loop) |
+----+-------------+----------+------------+-------+---------------+-------------------+---------+------+---------+----------+-----------------------------------------------------------------+

Вариант 2:

EXPLAIN
SELECT *
FROM ny_clean as n
WHERE n.id NOT IN (
    SELECT id 
    FROM pickup_0_ids_temp_table);
+----+--------------------+-------------------------+------------+-----------------+------------------------+---------+---------+------+---------+----------+-------------+
| id | select_type        | table                   | partitions | type            | possible_keys          | key     | key_len | ref  | rows    | filtered | Extra       |
+----+--------------------+-------------------------+------------+-----------------+------------------------+---------+---------+------+---------+----------+-------------+
|  1 | PRIMARY            | n                       | NULL       | ALL             | NULL                   | NULL    | NULL    | NULL | 3445904 |   100.00 | Using where |
|  2 | DEPENDENT SUBQUERY | pickup_0_ids_temp_table | NULL       | unique_subquery | PRIMARY,btree_pickup_0 | PRIMARY | 11      | func |       1 |   100.00 | Using index |
+----+--------------------+-------------------------+------------+-----------------+------------------------+---------+---------+------+---------+----------+-------------+

Затем я использую один из вариантов внутри этого более крупного запроса

EXPLAIN
INSERT INTO y    
SELECT id, pickup_longitude, pickup_latitude 
FROM x
JOIN 
(OPTION 1 OR 2) as z
ON z.id =  x.id;

Когда я использовал вариант 1 внутри более крупного запроса, он выполнялся в течение двух дней и не был завершен. Вариант 2, с другой стороны, сделал работу менее чем за 30 минут

Мой вопрос: почему это так? Следуя документации MySQL (https://dev.mysql.com/doc/refman/5.7/en/subquery-materialization.html), я подозреваю, что это связано с материализацией подзапроса, но как мне это проверить?

И я неправильно интерпретирую вывод EXPLAIN? Поскольку, исходя из этого, я ожидаю, что вариант 1 будет быстрее, поскольку он использует индекс для обеих таблиц

Или это нужно сделать с большим запросом?

Заранее спасибо

1 Ответ

0 голосов
/ 29 октября 2018

Ваш вариант 1 не делает то, что вы думаете, будет делать.

Если у вас две таблицы

      n.id            t.id
      1               1
      2               2 
      3               3

ON n.id != t.id;

Вы получаете:

   1,2
   1,3
   2,1
   2,3
   3,1
   3,2

Это почти декартово произведение. Итак, 3,4 м х 2,7 м ~ 9,18 мельничных рядов

Затем вы пытаетесь выполнить JOIN, и поскольку эта материализованная таблица не имеет индекса, потребуется очень много времени.

...