#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