2014-01-30 5 views
-1

У меня есть запрос MySQL, который отображает пользователей к зонам в зависимости от их расположения, а также границы зон:Переписать SQL подзапрос с ЗАКАЗА ... LIMIT с помощью JOIN

UPDATE User u SET u.zoneId = (
    SELECT z.id FROM Zone z 
    WHERE ST_Contains(z.boundary, u.location) 
    ORDER BY z.level DESC 
    LIMIT 1 
); 

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

Можно ли переписать его с помощью JOIN, хотя он использует ORDER BY ... LIMIT 1 в подзапросе?

Этот ORDER BY ... LIMIT 1 необходим, поскольку несколько инкапсулированных зон могут соответствовать местоположению, и должен быть назначен только самый маленький (самый высокий уровень).

+0

@ user2864740 Можете ли вы разработать ..? – Benjamin

+0

На самом деле, я не уверен, так как это ОБНОВЛЕНИЕ - суб-выбор - это просто выбрать значение. – user2864740

+0

1.) Я предполагаю, что ST_Contains (z.boundary, u.location) является хранимой процедурой. Не могли бы вы отредактировать запрос, чтобы прервать это и сделать его видимым для всех нас. 2.) Используйте EXPLAIN, чтобы понять, как оптимизатор обрабатывает ваш запрос. Вы всегда должны использовать EXPLAIN при создании запросов в качестве индексов, которые у вас есть или нет, могут иметь большое значение для производительности. –

ответ

0

В отсутствие каких-либо тестовых данных или полных DDL я не могу это проверить, но это может сработать. Использование объединений и вспомогательного запроса, но похоронив дополнительный запрос на дополнительный уровень, который может позволить MySQL игнорировать его использование таблицы для обновления в подзапросе.

Опирается на таблицу пользователя, имеющую уникальный ключ (я только что принял его как называемый id).

UPDATE User u 
INNER JOIN Zone z 
ON ST_Contains(z.boundary, u.location) 
INNER JOIN 
(
    SELECT id, MaxLevel 
    FROM 
    (
     SELECT u.id, MAX(z.level) AS MaxLevel 
     FROM User u 
     INNER JOIN Zone z 
     ON ST_Contains(z.boundary, u.location) 
     GROUP BY u.id 
    ) Sub1 
) Sub2 
ON u.id = Sub2.id AND z.level = Sub2.MaxLevel 
SET u.zoneId = z.id 

Если вы можете настроить некоторые тестовые данные в скрипте SQL, я могу проверить это.

+0

Разве это не будет быстрее? Насколько я вижу, все еще есть подзапрос. – Benjamin

+0

Разница заключается в том, что ваш исходный запрос использует коррелированный подзапрос, поэтому для каждой строки, подлежащей обновлению, mysql должен выполнить выбор.Если количество записей довольно ограничено, коррелированный подзапрос, вероятно, будет работать плохо. – Kickstart

+0

Вы имеете в виду, что ваш выполнил бы подзапрос только один раз? – Benjamin

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