2016-12-16 4 views
2

Что такое differenct в этом SQL:MySQL: разница между выберите * из таблицы и выберите * от (выберите * из таблицы)

первый:

select * 
    from table_1 a 
    join table_2 b 
    on a.id = b.acc_id 

второй:

select * 
    from (select * from table_1) a 
    join (select * from table_2) b 
    on a.id = b.acc_id 

Поскольку первый выполняется почти 40+ минут, а второй в течение нескольких секунд ...

Я действительно путаю редактор

Возможно, конфигурация MySQL DB нарушена?

Обе таблицы InnoDB и размещены на Domo

+0

Хотите знать, как вы пришли к тому факту –

ответ

3

Я очень удивлен, что вы сообщаете в запросе без подзапросов занимает так много времени. Я ожидал бы противоположного. Вы уверены, что правильно это заметили?

MySQL способен переписывать некоторые подзапросы, подобные тому, который вы показываете, если подзапрос достаточно прост. Поэтому не должно быть разницы.

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

При использовании подзапроса в качестве таблицы MySQL может потребоваться создать временную таблицу для хранения результата подзапроса, а затем использовать эту временную таблицу для последующих объединений или поиска или сортировки.

Временные таблицы создают накладные расходы для запроса, поскольку их необходимо сохранить. Если они маленькие, временная таблица может находиться в ОЗУ. Но если объем данных слишком велик, он скопирует таблицу на диск в каталоге, указанном в параметре конфигурации tmpdir.

Вы также должны собрать некоторую информацию о том, как MySQL собирается запустить свой запрос:

EXPLAIN select * 
    from (select * from table_1) a 
    join (select * from table_2) b 
    on a.id = b.acc_id\G 

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: b 
    partitions: NULL 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 1 
    filtered: 100.00 
     Extra: Using where 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: a 
    partitions: NULL 
     type: eq_ref 
possible_keys: PRIMARY,id 
      key: PRIMARY 
     key_len: 8 
      ref: test.b.acc_id 
     rows: 1 
    filtered: 100.00 
     Extra: NULL 

В этом простом примере, EXPLAIN отчет точно так же, как если бы мы запустили этот эквивалентный запрос:

EXPLAIN select * 
    from table_1 a 
    join table_2 b 
    on a.id = b.acc_id\G 

По крайней мере, поскольку я проверяю это на MySQL 8.0.0-dmr. Старые версии MySQL могут не поддерживать эту оптимизацию.

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

Вы также должны убедиться, что таблицы имеют нужные индексы, чтобы позволить объединению выполнять поиск индекса для соединения. В отчете EXPLAIN вы должны увидеть второй отчет таблицы «type: ref» или «type: eq_ref».

При запросе вопросов SQL это поможет, если вы разместите фактический запрос, который дал вам 40-минутное время запроса. А также запустите SHOW CREATE TABLE для каждой таблицы в соединении, чтобы мы могли видеть, какие индексы и ограничения у вас есть в каждой таблице.

Обновление: Я запустил тот же отчет EXPLAIN на MySQL 5.6.33, и мы можем видеть, производные таблицы, созданные из подзапросов:

*************************** 1. row *************************** 
      id: 1 
    select_type: PRIMARY 
     table: <derived2> 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 2 
     Extra: NULL 
*************************** 2. row *************************** 
      id: 1 
    select_type: PRIMARY 
     table: <derived3> 
     type: ref 
possible_keys: <auto_key0> 
      key: <auto_key0> 
     key_len: 9 
      ref: a.id 
     rows: 2 
     Extra: NULL 
*************************** 3. row *************************** 
      id: 3 
    select_type: DERIVED 
     table: table_2 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 1 
     Extra: NULL 
*************************** 4. row *************************** 
      id: 2 
    select_type: DERIVED 
     table: table_1 
     type: ALL 
possible_keys: NULL 
      key: NULL 
     key_len: NULL 
      ref: NULL 
     rows: 1 
     Extra: NULL 
+1

Старые версии MySQL собираются заставить точку инлайн быть материализовались в виде производных таблиц, перед тем выполняется внешний запрос. И я тоже ожидал, что версия с производными таблицами займет больше времени для выполнения. Но я также выбрал время для «первого запуска» каждого заявления. Я не хочу сравнивать время выполнения «холодного кеш-диска io» и «утепленного кеша». И я не рассматриваю кеш запросов MySQL для искажения результатов, поэтому, если это разрешено, я бы хотел сравнить только время выполнения 'SELECT SQL_NO_CACHE' ... +10 – spencer7593