Будет ли это при условии во внешнем соединении быстрее, чем в предложении where?

Вот мой стол

CREATE TABLE log_table (
  `user_id` VARCHAR(5),
  `date_time` DATETIME,
  `event_name` VARCHAR(10),
  `trivial` int
);

INSERT INTO log_table
  (`user_id`, `date_time`, `event_name`, `trivial`)
VALUES
  ('001', '2020-12-10 10:00:02', 'c', 3),
  ('001', '2020-12-10 10:00:01', 'b', 9),
  ('001', '2020-12-10 10:00:40', 'e', 2),
  ('001', '2020-12-10 10:00:20', 'd', 6),
  ('001', '2020-12-10 10:00:00', 'a', 1),
  ('002', '2020-12-09 10:00:10', 'C', 9),
  ('002', '2020-12-10 10:00:50', 'D', 0),
  ('002', '2020-12-10 10:00:02', 'A', 2),
  ('002', '2020-12-10 10:00:09', 'B', 4);

(создано на DB Fiddle)

Я хочу найти одного человека (любого), который вызвал имя события, и получить все записи этого пользователя в этот день.

user_id date_time event_name trivial trivial_new
001 2020-12-10 10:00:00 a 1 13
001 2020-12-10 10:00:01 b 9 19
001 2020-12-10 10:00:02 c 3 21
001 2020-12-10 10:00:20 d 6 20
001 2020-12-10 10:00:40 e 2 11
002 2020-12-09 10:00:02 A 2 15
002 2020-12-10 10:00:09 B 4 15
002 2020-12-10 10:00:10 C 9 15
002 2020-12-10 10:00:50 D 0 13

Вот мой код:

SELECT t_left.*
FROM   log_table AS t_left
       RIGHT JOIN (SELECT user_id,
                          date_time
                   FROM   log_table
                   WHERE  BINARY event_name = 'B'
                   LIMIT  1) AS t_right
               ON t_left.user_id = t_right.user_id
                  AND Substring_index(t_left.date_time, ' ', 1) =
                      Substring_index(t_right.date_time, ' ', 1)
ORDER  BY date_time 

В правой таблице была бы только одна запись, которая удовлетворяет условиям, что event_name это B, то есть пользователь с id 002. И затем я присоединяю ее к левой таблице при условии, что их user_id равны, а дата равна 2020-12-10, удаление других пользователей с другими id, 001 и записи того же человека, события которого произошли не 2020-12-10.

Все работает хорошо.

Затем я изменил свой код, чтобы проверить, будет ли он работать так, как я ожидал (так и произошло, см. здесь):

SELECT t_left.*
FROM   log_table AS t_left
       RIGHT JOIN (SELECT user_id,
                          date_time
                   FROM   log_table
                   WHERE  BINARY event_name = 'B'
                   LIMIT  1) AS t_right
               ON t_left.user_id = t_right.user_id
WHERE  Substring_index(t_left.date_time, ' ', 1) =
       Substring_index(t_right.date_time, ' ', 1)
ORDER  BY date_time 

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

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

Интересно, в моем случае первый будет быстрее?

Любая онлайн-платформа для сравнения скорости?


person Lerner Zhang    schedule 30.01.2021    source источник
comment
Не утверждаю, что это будет быстрее, но я предпочитаю использовать DATE(t_left.date_time) вместо SUBSTRING_INDEX(t_left.date_time, ' ', 1) для извлечения даты.   -  person FaNo_FN    schedule 30.01.2021
comment
Эти запросы являются той же функцией ввода, только если вы могли бы использовать внутреннее соединение, а не правое соединение, т. е. если правая таблица никогда не имеет несовпадающих строк. Ваш where верен только для строк с ненулевыми датами левой таблицы, поэтому вы можете просто использовать внутреннее соединение. В чем смысл правильного соединения? Если вам нужно правильное соединение, ваш второй запрос неверен - и производительность спорна. PS Пожалуйста: изучите, прежде чем спрашивать, и отражайте исследования. Прежде чем спрашивать о производительности SQL, изучите ее и спросите об этом. PS Пожалуйста, помещайте все необходимое, чтобы спросить в своем посте, а не на скрипке.   -  person philipxy    schedule 30.01.2021
comment
@philipxy Спасибо за предложения. Я выучил SQL 8 лет назад и только начал его использовать. Ответы в другом месте ошеломили меня.   -  person Lerner Zhang    schedule 30.01.2021
comment
*Пожалуйста, перепишите, чтобы использовать LEFT JOIN вместо RIGHT JOIN.)   -  person Rick James    schedule 30.01.2021
comment
@RickJames Хорошо, дай посмотреть. Спасибо.   -  person Lerner Zhang    schedule 30.01.2021
comment
Почему бы не сравнить производительность в автономном режиме? Кстати, обратите внимание, что никто никогда не использует RIGHT JOIN.   -  person Strawberry    schedule 30.01.2021
comment
Все обсуждения производительности неуместны, потому что это то, что убивает вашу производительность: AND Substring_index(t_left.date_time, ' ', 1) = Substring_index(t_right.date_time, ' ', 1)   -  person Strawberry    schedule 30.01.2021


Ответы (2)


ON следует использовать, чтобы указать, как связаны таблицы.

WHERE следует использовать для фильтрации.

Для простых JOIN (INNER JOIN) они реализованы одинаково.

Для ЛЕВОГО/ПРАВОГО они могут иметь большое значение.

person Rick James    schedule 30.01.2021

Если предполагается, что второй запрос будет окончательной структурой запроса, вам больше не нужно использовать RIGHT JOIN, это особенно верно, поскольку вы сопоставляете даты в WHERE вместо ON.. эффективно отменяя правое соединение (или левое соединение) . На самом деле, поскольку вы выполняете правое соединение с подзапросом, который извлекает только определенные данные для таблицы справа, вряд ли есть какая-либо причина для правого соединения, вы получите больше различий в результатах, если вместо этого выполните левое соединение. Кроме того, по моему опыту, JOIN (INNER JOIN) обычно намного быстрее, чем левое/правое соединение.

Другое дело, что индексы сильно влияют на производительность. В вашем текущем примере не было индексов, поэтому я рекомендую вам это сделать. Я многое узнал об индексировании на этой странице @Rick James.

Вот скрипт, основанный на дате вашего примера, состоящей из вашей первоначальной попытки и еще нескольких:

  1. RIGHT JOIN .. ON ... AND
  2. RIGHT JOIN .. ON ... WHERE
  3. LEFT JOIN .. ON ... AND
  4. LEFT JOIN .. ON ... WHERE
  5. добавление индекса
  6. EXPLAIN до и после index.

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=1b244deb6fad0dda0bf4aaf701e6bac2

PS: В скрипке я изменил извлечение даты, чтобы использовать DATE().

person FaNo_FN    schedule 01.02.2021