Как я могу оптимизировать этот запрос с помощью подзапроса? - PullRequest
2 голосов
/ 26 января 2012

У меня следующий запрос MySQL:

SELECT value_1, (
    SELECT value_4 
    FROM table_1
    WHERE value_3 < value_1 
    ORDER BY value_3 DESC  
    LIMIT 1
)
AS result_value 
FROM table_2 
WHERE value_1 BETWEEN 1325372400000 AND 1328050800000  
ORDER BY value_1

, который возвращает 32 результата и занимает 6,6 секунды. Идея состоит в том, чтобы получить записи из таблицы_1, где значение_3 является «ближайшим» к значению_1 в таблице_2.

Два запроса, из которых состоит запрос, а именно

SELECT value_1
AS result_value 
FROM table_2 
WHERE value_1 BETWEEN 1325372400000 AND 1328050800000  
ORDER BY value_1

и (например)

SELECT value_4 
FROM table_1
WHERE value_3 < 1328050800000 
ORDER BY value_3 DESC  
LIMIT 1

каждый занимает 0,03 секунды для запуска. При вычислении суммарного времени для 32 наборов результатов составной запрос должен занимать не более 1 секунды или, возможно, даже меньше (поскольку не учитываются издержки ввода-вывода для отдельных запросов). И все же на 6,6 секунды это занимает гораздо больше времени.

Почему, как я могу его оптимизировать? Или есть другой / превосходный способ достичь моей цели?

Обновление:

Таблица определений:

таблица_1 (MyISAM, 700000 записей):

'id', 'int(10) unsigned', 'NO', 'PRI', NULL, 'auto_increment'
'value_3', 'bigint(20) unsigned', 'NO', 'UNI', '0', ''
'value_4', 'bigint(20) unsigned', 'NO', '', '0', ''

таблица_2 (MyISAM, 4000 записей):

'value_1', 'bigint(20) unsigned', 'NO', 'PRI', NULL, ''

ОБЪЯСНИТЬ [запрос]:

'1', 'PRIMARY', 'table_2', 'range', 'PRIMARY,value_3_UNIQUE', 'PRIMARY', '8', NULL, '32', 'Using where; Using index'
'2', 'DEPENDENT SUBQUERY', 'table_1', 'index', 'value_3,value_3_value_4', 'value_3', '8', NULL, '1', 'Using where'

Ответы [ 3 ]

1 голос
/ 26 января 2012

Если у вас есть индекс на value_1 в table_2 и составной (value3, value4) индекс на table_1, то в запросе будут использоваться только индексы.


Вы также можете попробовать этот запрос:

SELECT value_1
     , value_4 AS result_value 
FROM table_2 
  JOIN table_1
    ON table_1.value_3 =
       ( SELECT value_3
         FROM table_1
         WHERE value_3 < value_1 
         ORDER BY value_3 DESC  
         LIMIT 1
       )
WHERE value_1 BETWEEN 1325372400000 AND 1328050800000  
ORDER BY value_1
1 голос
/ 26 января 2012

Используйте немного mysql кунг-фу:

SELECT * from
(SELECT value_1, value_4
FROM table_2 
join table_1 on value_3 < value_1
WHERE value_1 BETWEEN 1325372400000 AND 1328050800000  
ORDER BY value_1, value_3 DESC) x
GROUP BY value_1 
ORDER BY value_1

"Кунг-фу" заключается в том, что с mysql, когда столбцы, по которым вы не группируете, не агрегируются (например, SUM() и т. Д.), Выполучить первую строку, найденную для каждой группы.Если вы используете эту технику в упорядоченном результирующем наборе, вы можете получить значение, которое вам нужно.

Мало того, что это легче кодировать, но вы заметите, что для таблиц выполняется только один проход (не один запрос на строку, как вы пытались).Он должен хорошо работать.

Редактировать:

Некоторые комментаторы высказывали предположение, что эта специальная форма GROUP BY является "неопределенной" и / или "официально не поддерживается" и т. Д. Документация заявляет, что строка, выбранная в «неопределенном», однако я никогда не видел и не слышал о том, чтобы mysql выбирал какую-либо строку , отличную от , чем первая, с которой встречается и с помощью order by для внутреннего выбора используется и полагается вбесчисленные производственные запросы.

FWIW, я рад рекомендовать этот подход как «надежный» и достойный производства.

0 голосов
/ 26 января 2012

Здесь я просто избегаю использования виртуальной (производной) таблицы.Основной причиной использования виртуальных таблиц была сортировка, которая была достигнута путем применения предложения order by в groupcconcat ().

SELECT SUBSTRING_INDEX(group_concat(value_1 
                                    ORDER BY value_1, value_3 DESC),',',1) as value_1, 
       SUBSTRING_INDEX(group_concat(value_4
                                    ORDER BY value_1, value_3 DESC),',',1) as value_4 
FROM table_2 join table_1 on value_3 < value_1 

WHERE value_1 BETWEEN 1325372400000 AND 1328050800000  

GROUP BY value_1  
ORDER BY value_1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...