Привет, у меня есть разбиение на страницы в угловых js в моем приложении, я отправляю данные в свой большой запрос, который включает фильтры, которые пользователь установил
UPDATE SQL_CALC_FOUND_ROWS это моя проблема. Как подсчитать строки определенных фильтров. Мне понадобилось 2 секунды для 100 000 строк Мне нужен номер для разбивки на страницы в виде общего числа
UPDATE: У меня есть следующий внутренний запрос, который я пропустил здесь:
(выберите count (*) от студентов как inner_st, где st.name = inner_st.name) в качестве имен,
когда я удаляю внутренний запрос намного быстрее
строки: 50 000 Таблица пользователей: 4 строки Таблица классов: 4 строки индексов: только id как первичный ключ
время запроса 20-40 секунд
tables: students.
columns : id, date ,class, name,image,status,user_id,active
table user
coloumn: id,full_name,is_admin
запрос
SELECT SQL_CALC_FOUND_ROWS st.id,
st.date,
st.image,
st.user_id,
st.status,
st,
ck.name AS class_name,
users.full_name,
(select count(*) from students AS inner_st where st.name = inner_st.name) AS names,
FROM students AS st
LEFT JOIN users ON st.user_id = users.user_id
LEFT JOIN classes AS ck ON st.class = ck.id
WHERE date BETWEEN '2018-01-17' AND DATE_ADD('2018-01-17', INTERVAL 1 DAY)
AND DATE_FORMAT(date,'%H:%i') >= '00:00'
AND DATE_FORMAT(date,'%H:%i') <= '23:59'
AND st.active=1
-- here I can concat filters from web like "and class= 1"
ORDER BY st.date DESC
LIMIT 0, 10
Как я могу сделать это быстрее? когда я удаляю порядок и SQL_CALC_FOUND_ROWS быстрее, но я нуждаюсь в них, я слышал об индексах, но только первичный ключ - индекс
Несколько комментариев, прежде чем рекомендовать другой подход к этому запросу:
SQL_CALC_FOUND_ROWS
удалить SQL_CALC_FOUND_ROWS
и вместо этого запустить два запроса (один, который подсчитывает, и тот, который выбирает данные)? В некоторых случаях это может быть быстрее, чем объединение их обоих в один запрос.AND DATE_FORMAT(st.date, '%H:%i') >= '00:00' AND DATE_FORMAT(st.date, '%H:%i') <= '23:59'
Чтобы оптимизировать запрос, давайте начнем с добавления этих индексов:
ALTER TABLE 'classes' ADD INDEX 'classes_index_1' ('id', 'name');
ALTER TABLE 'students' ADD INDEX 'students_index_1' ('active', 'user_id', 'class', 'name', 'date');
ALTER TABLE 'users' ADD INDEX 'users_index_1' ('user_id', 'full_name');
Теперь создайте временную таблицу (первоначально это был подзапрос в предложении SELECT) и проиндексировали ее:
-- Transformed subquery to a temp table to improve performance
CREATE TEMPORARY TABLE IF NOT EXISTS temp1 AS SELECT
count(*) AS names,
name
FROM
students AS inner_st
WHERE
1 = 1
GROUP BY
name
ORDER BY
NULL
-- This index is required for optimal temp tables performance
ALTER TABLE
'temp1'
ADD
INDEX 'temp1_index_1' ('name', 'names');
И измененный запрос:
SELECT
SQL_CALC_FOUND_ROWS st.id,
st.date,
st.image,
st.user_id,
st.status,
ck.name AS class_name,
users.full_name,
temp1.names
FROM
students AS st
LEFT JOIN
users
ON st.user_id = users.user_id
LEFT JOIN
classes AS ck
ON st.class = ck.id
LEFT JOIN
temp1
ON st.name = temp1.name
WHERE
st.date BETWEEN '2018-01-17' AND DATE_ADD('2018-01-17', INTERVAL 1 DAY)
AND st.active = 1
ORDER BY
st.date DESC LIMIT 0,
10
Попробуйте сначала:
INDEX(active, date)
Пользователь user_id
PK для users
? Является ли class_id
PK для classes
? Если нет, то они должны быть INDEXed
.
Почему вы проверяете время раздельно?
Исправьте тест, так что очевидно, какая таблица находится в каждом столбце.
Вам действительно нужно LEFT JOIN
? Или JOIN
хватает? В последнем случае есть больше вариантов оптимизации.
Дайте некоторые реалистичные примеры других SELECTs
; может потребоваться другой индекс (ы).
"Первая" страница медленная? Или только более поздние страницы? См. Это для оптимизации разбиения на страницы - не используя OFFSET
.