Как оптимизировать этот запрос внутреннего соединения, чтобы уменьшить время запроса - PullRequest
0 голосов
/ 13 апреля 2019

У меня есть таблица, которая теперь имеет около 1 м строк.Следующий запрос должен занять около 5 секунд.Что вы предлагаете оптимизировать скорость запросов?

# Thread_id: 14  Schema: defrop_defrop  QC_hit: No
# Query_time: 5.573048  Lock_time: 0.591625  Rows_sent: 0  Rows_examined: 1006391
# Rows_affected: 1
UPDATE `backlinks` as a
INNER JOIN(SELECT b.`id` as bid
           FROM `backlinks` b
           WHERE b.`googlebot_id` IS NULL AND b.`used_time` IS NULL AND 
b.`campaign_id` IN  (SELECT `id` FROM `campaigns` WHERE `status`=true) GROUP BY b.`campaign_id` ORDER BY RAND() limit 1
           ) as c
 ON (a.id = c.bid)
SET a.`crawler_id` = '10.0.0.13', a.`used_time`=NOW();

campaign_id, googlebot_id - это внешние ключи, индексаторы.used_time и crawler_id являются индексаторами Скриншот из таблицы phpmyadmin Phpmyadmin table backlinks

1 Ответ

2 голосов
/ 13 апреля 2019

Этот запрос отформатирован, поэтому я могу прочитать его лучше:

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;

Это значительно ускоряет сортировку, потому что она находится на сотых данных. Тем не менее, он может отфильтровать все строки - если недостаточно строк соответствуют условиям.

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