Этот запрос отформатирован, поэтому я могу прочитать его лучше:
UPDATE backlinks bl JOIN
(SELECT bl2.id as bid
FROM backlinks bl2
WHERE bl2.googlebot_id IS NULL AND
bl2.used_time IS NULL AND
bl2.campaign_id IN (SELECT c.id FROM campaigns c WHERE status = true)
GROUP BY b.campaign_id
ORDER BY RAND()
LIMIT 1
) bl2
ON bl.id = bl2.bid
SET bl.crawler_id = '10.0.0.13',
bl.used_time = NOW();
Во-первых, GROUP BY
в подзапросе не требуется. И я бы заменил IN
на EXISTS
:
UPDATE backlinks bl JOIN
(SELECT bl2.id as bid
FROM backlinks bl2
WHERE bl2.googlebot_id IS NULL AND
bl2.used_time IS NULL AND
EXISTS (SELECT 1 FROM campaigns c WHERE bl2.campaign_id = c.id AND c.status = true)
ORDER BY RAND()
LIMIT 1
) bl2
ON bl.id = bl2.bid
SET bl.crawler_id = '10.0.0.13',
bl.used_time = NOW();
Это поможет немного, но, вероятно, не сильно. Я предполагаю, что проблема производительности заключается в размере внешней сортировки (или, что эквивалентно, размере данных, необходимых для GROUP BY
в вашем запросе).
Вы также можете полностью избавиться от подзапроса:
UPDATE backlinks bl
SET bl.crawler_id = '10.0.0.13',
bl.used_time = NOW()
WHERE bl.googlebot_id IS NULL AND
bl.used_time IS NULL AND
EXISTS (SELECT 1 FROM campaigns c WHERE bl.campaign_id = c.id AND c.status = true)
ORDER BY RAND()
LIMIT 1;
Это оказывает минимальное влияние, но немного очищает логику.
Я предполагаю, что условия WHERE
не очень избирательны, поэтому их оптимизация не сильно поможет.
На данный момент проблема заключается в ORDER BY RAND()
. Если у вас есть представление о том, сколько строк возвращается подзапросом, вы можете выполнить предварительную фильтрацию, используя RAND()
. Например, позвольте мне предположить, что возвращено как минимум 1000 строк. Тогда:
UPDATE backlinks bl
SET bl.crawler_id = '10.0.0.13',
bl.used_time = NOW()
WHERE bl.googlebot_id IS NULL AND
bl.used_time IS NULL AND
EXISTS (SELECT 1 FROM campaigns c WHERE bl.campaign_id = c.id AND c.status = true) AND
RAND() < 0.01 -- keep about 1/100
ORDER BY RAND()
LIMIT 1;
Это значительно ускоряет сортировку, потому что она находится на сотых данных. Тем не менее, он может отфильтровать все строки - если недостаточно строк соответствуют условиям.