2013-10-09 3 views
0

Мне нужно объединить две таблицы с одинаковыми столбцами и использовать результат в сложных JOIN-запросах, но это сильно ухудшает производительность. Этот запрос с союзами имеет время выполнения 7 секунд:mySQL - выполнение операторов UNION

SELECT DISTINCT `admin`.`Fund_ID`, 
       `admin`.`Fund_Name` 
FROM (
     (SELECT * 
     FROM `admin`) 
     UNION 
     (SELECT * 
     FROM `admin_custom` 
     WHERE `user_id`=361)) admin 
LEFT JOIN (
      (SELECT * 
       FROM `quant1`) 
      UNION 
      (SELECT * 
       FROM `quant1_cust` 
       WHERE `user_id`=361)) quant1 
ON (quant1.`Fund ID`=`admin`.`Fund_ID`) 
WHERE quant1.`VaR 95`>-0.028 

Но заменив пункт UNION простым столом делает это лишь 0,006 сек. Как я могу исправить проблемы с производительностью?

+0

Вы уверены, что вы ** ДОЛЖНЫ ** использовать UNION? Могут ли быть дубликаты (поскольку разница между UNION и UNION ALL заключается в удалении дубликатов), если нет, вы можете использовать UNION ALL –

+0

Индексирование - это почти наверняка ответ. Используйте 'EXPLAIN' в вашем запросе, чтобы узнать, что делает MySQL, а затем посмотрите на индексацию самых медленных частей. –

+1

Нет необходимости в 'внешнем соединении', так как вы включаете этот результат в свои критерии' where' ... – user2480596

ответ

0

Вы можете сделать «добавление изменений» в базу данных, чтобы создать общность между таблицами UNIONED. Это будет рефакторинг, который добавляет только таблицы & столбцы, сохраняя совместимость чтения с неизменным кодом приложения.

В этом примере вы должны создать общую таблицу «слева» от admin и admin_custom, которая затем будет соединена с ней. У этого будет ID фонда, ТИП (чтобы вы знали, к чему присоединяетесь) и, если возможно, другие полезные общие столбцы.

Вы также создать общую таблицу «слева» quant1 и quant1_cust, которые затем будут присоединяться из , что.

Затем вы изменили запрос на использование ссылки на идентификатор фонда из общих таблиц, заменив свои позиции UNION либо просто «общей таблицей» (если возможно), либо "Common Table" left outer join Legacy1 left outer join Legacy2.

Я не понимаю «что» эти таблицы на самом деле, поэтому я не могу помочь вам с разумным наименованием. (Именование - самая важная часть дизайна, и вы должны были объяснить это в своем вопросе.)

Но этот подход очень хорошо работал для крупного проекта правительства, который я возглавлял, где общие таблицы были ДОКУМЕНТОМ и DOC_ELEMENT. Деревоструктурированные документы с 8 различными типами документов и без ранее существовавшей общности.

В нашем случае ДОКУМЕНТ был добавлен «слева от» RFP, TENDER, PRICEPLAN и т. Д. И обеспечил общность.

Это не полная совместимость в обратном направлении - вам нужно будет изменить код INSERT приложения. И если вы переходите на рефакторинг, вы можете рассмотреть , помещая ту же структуру таблицы в ту же таблицу.

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

+0

Я не могу присоединиться к этой таблице в «Find ID», потому что нет общих идентификаторов фондов: эти таблицы имеют идентичную структуру и не имеют общих значений ключа. Подумайте об этих СОЕДИНЕННЫХ столах как одинарной таблице, разрезанной пополам. – user2723490

+0

Вот как я это понял. «Присоединение к Fund_ID» относится к общей «LEFT JOIN» вашего запроса, которая - как указано - говорит, что она находится в ID фонда. Возможно, я мог бы объяснить гораздо более четко, если ваш вопрос определил, на самом деле, что UNIONed таблицы логически (как с левой стороны, так и справа) и рассказал нам о своих ПК. Как бы то ни было, из-за отсутствия деталей от вас я не мог быть точным, и вы неправильно читали мой ответ. ** Прочитайте его еще раз и напишите логический смысл ваших UNIONed таблиц и их ПК. ** –

0

Это связано с некоторыми догадками - admin относится только к quant1? и admin_custom только quant1_cust? Тогда это должно уменьшить усилие, необходимое для отдельного списка этих 2-х полей:

SELECT `Fund_ID`, `Fund_Name` 
FROM `admin` 
INNER JOIN `quant1` ON `admin`.`Fund_ID` = `quant1`.`Fund_ID` 
        AND `quant1`.`VaR 95`>-0.028 

UNION 

SELECT `Fund_ID`, `Fund_Name` 
FROM `admin_custom` 
INNER JOIN `quant1_cust` ON `admin_custom`.`Fund_ID` = `quant1_cust`.`Fund_ID` 
         AND `admin_custom`.`user_id` = `quant1_cust`.`user_id` 
         AND `quant1_cust`.`VaR 95`>-0.028 
WHERE `admin_custom`.`user_id`=361 
; 

Глядя на существующую структуру запроса есть несколько вещей, которые я хотел бы предложить вам не делать. Нет смысла использовать UNION и SELECT DISTINCT. Не используйте select * с UNION или UNION ALL - будьте конкретными и используйте только те поля, которые вам действительно нужны. И ваше существующее предложение where подавляет любые значения, возвращаемые левым соединением, поэтому не используйте левое соединение.

SELECT DISTINCT --<< effort for distinctiveness here 
... 
FROM (
     SELECT * --<< too many fields 
     ... 
     UNION --<< effort for distinctiveness here 

     SELECT * --<< too many fields 
     ... 
    ) 
LEFT JOIN (
      SELECT * --<< too many fields 
      ... 
      UNION --<< effort for distinctiveness here 

      SELECT * --<< too many fields 
      ... 
      ) quant1 
WHERE quant1 ... 

редактировать: альтернативный - извините, это может быть легче следовать таким образом:

SELECT `Fund_ID`, `Fund_Name` 
FROM `admin` 
INNER JOIN `quant1` ON `admin`.`Fund_ID` = `quant1`.`Fund_ID` 
WHERE `quant1`.`VaR 95`>-0.028 

UNION 

SELECT `Fund_ID`, `Fund_Name` 
FROM `admin_custom` 
INNER JOIN `quant1_cust` ON `admin_custom`.`Fund_ID` = `quant1_cust`.`Fund_ID` 
         AND `admin_custom`.`user_id` = `quant1_cust`.`user_id` 
WHERE `admin_custom`.`user_id`=361 
AND `quant1_cust`.`VaR 95`>-0.028 
; 
+0

Я играю с различными вариантами в течение дня или около того, и похоже, что UNION - очень плохой способ. Пример кода - всего лишь фрагмент динамически построенного предложения WHERE, в то время как он может содержать 15-20 полей. Вот почему мне нужен UNION. Я думаю, что проблема связана с большими таблицами UNIONing: таблица UNIONed не индексируется - вот почему дальнейшие запросы SELECT очень медленные. Лучшим решением, которое я нашел до сих пор, является INSERT SELECT содержимое второй таблицы и работа с единой таблицей для всех объединений. Гораздо быстрее, но мне нужно будет синхронизировать эти таблицы. – user2723490

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

  • Нет связанных вопросов^_^