оптимизация запросов mariadb для вложенных запросов

#mysql #sql #mariadb

Вопрос:

У меня был запрос, внутри которого есть три «выбора». Я предполагаю, что он выполняется в O (n ^ 3) и вообще неэффективен, для возврата 10 строк требуется 6 секунд, для 200 строк требуется 55 секунд, а для 1000 строк требуется более 3 минут, я действительно понятия не имею, как я мог бы сделать это лучше и быстрее.

версия mariadb: 10.4.20-MariaDB

запрос :

 SELECT review.* FROM (SELECT review.* , 
                          (SELECT MIN(t2.id) FROM review t2 
                            WHERE t2.reviewcount = 0 
                            AND t2.fcid = review.fcid 
                            AND `userid` = :uid) as min_id
                      FROM review
                      WHERE reviewcount = 0 
                      AND `userid` = :uid) 
                      review
                      WHERE id = min_id AND deckid = :did LIMIT :nums;
 

Комментарии:

1. Примеры данных, желаемые результаты и четкое объяснение того, чего вы хотите достичь, помогут.

2. Вам нужно показать нам определения таблиц и индексов , а также количество строк для каждой из таблиц. Возможно, ваши таблицы определены плохо. Возможно, индексы созданы неправильно. Возможно, у вас нет индекса в том столбце, который, как вы думали, у вас есть. Не видя определений таблиц и индексов, мы не можем сказать. Нам нужно количество строк, потому что это может повлиять на планирование запросов. Если вы знаете, как выполнить EXPLAIN или получить план выполнения, также укажите результаты в вопросе. Если у вас нет индексов, посетите use-the-index-luke.com .

3. @GordonLinoff Я просто хочу ускорить или разделить этот запрос, но я понятия не имею. Должен ли я также писать таблицы?

4. @AndyLester, хорошо, я обновлю вопрос

Ответ №1:

обзор должен иметь комбинированный индекс (fcid, id, userid , deckid , reviewcount)

Порядок столбцов — это то, что вы должны проверить

 SELECT r1.*       
FROM review r1
  INNER JOIN 
  (SELECT MIN(r2.id) min_id, fcid FROM review r2 
        WHERE t2.reviewcount = 0                             
        AND `userid` = :uid
        GROUP BY fcid) as r2
        ON r1.fcid = r2.fcid
  WHERE reviewcount = 0 
  AND `userid` = :uid
  AND  id = min_id AND deckid = :did 
  LIMIT :nums;
 

Ответ №2:

Ваш запрос упрощен:

 SELECT ...
FROM 
(
  SELECT
    review.*, 
    min(id) over (partition by userid, fcid) as min_id
  FROM review
  WHERE reviewcount = 0 
  AND userid = :uid
) r
WHERE id = min_id AND deckid = :did
LIMIT :nums;
 

Вы ищете отзывы пользователей, где количество отзывов равно нулю. Соответствующий индекс кажется, следовательно:

 create index idx1 on review (userid, reviewcount);
 

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

 create index idx2 on review (userid, reviewcount, fcid, id, deckid);
 

Ответ №3:

Я думаю, что если вы использовали CTE, а параллельная обработка вместо вложенных запросов позволит быстрее получать данные, вы можете посмотреть, как использовать CTE по этой ссылке: https://www.javatpoint.com/mysql-common-table-expression