Как я могу ускорить этот запрос SELECT CONCAT / GROUP BY? - PullRequest
1 голос
/ 31 июля 2009

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

SELECT CONCAT_WS(', ', city, state) as location, AVG(latitude), AVG(longitude) 
FROM places
WHERE city='New York' AND state='NY'
GROUP BY location

В любом случае в этом месте будет CONCAT, потому что я хочу, чтобы база данных возвращала симпатичную каскадную версию местоположения (если только в коде нет причин делать это). Например, «Нью-Йорк, Нью-Йорк». На самом деле, третий столбец иногда добавляется в микс (почтовый индекс). Я работаю на MySQL.

Как лучше всего оптимизировать этот запрос?

Кроме того, как дополнительный вопрос, может ли добавление "DISTINCT" замедлить запрос каким-либо образом? Например:

SELECT DISTINCT CONCAT_WS(', ', city, state) as location, AVG(latitude), AVG(longitude) 
FROM places
WHERE city='New York' AND state='NY'
GROUP BY location

(В настоящее время я делаю это сейчас, но, задавая этот вопрос, я понял, что DISTINCT не нужен из-за предложения GROUP BY; однако, поскольку в этом нет необходимости, мне интересно, имеет ли это какое-либо значение и если мне стоит потрясти лодку, чтобы ускорить запрос.)

Редактировать: уже есть индекс города, штата и почтового индекса; плюс их комбинации (город, почтовый индекс; только штат / почтовый индекс).

Ответы [ 4 ]

4 голосов
/ 31 июля 2009

Создайте составной индекс для (state, city) и перепишите ваш запрос следующим образом:

SELECT  CONCAT_WS(', ', city, state) AS location, AVG(latitude), AVG(longitude) 
FROM    places
WHERE   state='NY'
        AND city='New York'
GROUP BY
        state, city

Обратите внимание, что для этого самого запроса вы можете опустить предложение GROUP BY:

SELECT  'New York, NY' AS location, AVG(latitude), AVG(longitude) 
FROM    places
WHERE   state='NY'
        AND city='New York'

Однако, этот запрос все еще будет нуждаться в этом:

SELECT  CONCAT_WS(', ', city, state) AS location, AVG(latitude), AVG(longitude) 
FROM    places
WHERE   state='NY'
GROUP BY
        state, city
2 голосов
/ 31 июля 2009

Забавно, но почти все проблемы людей с базами данных - это скорость, а не требования к хранилищу. Это должно сказать вам кое-что: -)

У нас были подобные проблемы раньше, и я говорил это много раз: функции для каждой строки обычно плохо масштабируются. Наилучший способ их устранения - использование триггеров вставки / обновления (я предполагаю, что в MySQL они есть).

Создайте еще один столбец с вызовом pretty_city_state (или любым другим), и пусть триггеры заполняют его из города и штата при каждом добавлении или обновлении строки. Затем создайте для него индекс.

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

Попробуйте и измерите разницу - я уверен, что вы обнаружите, что ваши выборки будут кричать с минимальными затратами для триггеров (и эта стоимость полностью исчезнет, ​​когда у вас будут все города и штаты в вашей базе данных.

И да, я знаю, что это нарушает 3NF. Это вполне приемлемо по соображениям производительности , если вы знаете, что делаете .

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

SELECT pretty_city_state as location, AVG(latitude), AVG(longitude) 
FROM places
WHERE city='New York' AND state='NY'
GROUP BY pretty_city_state

или, может быть, даже быстрее (измерить, не угадать), если вы можете объединить город и штат перед началом запроса:

SELECT pretty_city_state as location, AVG(latitude), AVG(longitude) 
FROM places
WHERE pretty_city_state ='New York, NY'
GROUP BY pretty_city_state
0 голосов
/ 31 июля 2009

Поможет добавить индекс по полям "город" и "штат".

Кроме того, в зависимости от количества элементов в каждом поле (количество различных значений), версии MySQL, механизма таблиц и других параметров, инвертирование предложений WHERE может повлиять на время выполнения вашего запроса. Я бы попробовал:

WHERE state='NY' AND city='New York'
0 голосов
/ 31 июля 2009

Один из способов оптимизировать запрос, подобный этому, - установить эти столбцы в качестве столбцов индекса. Таким образом, он может легко сортировать / группировать на основе дерева или хеша. Кроме того, объединение строк также может иметь некоторые последствия.

...