Ускорение MySQL Queries / MySQL просмотров в Джангу
-
01-10-2019 - |
Вопрос
Я использую следующий код для выбора популярных новостей (по дате) из базы данных:
popular = Entry.objects.filter(type='A', is_public=True).extra(select = {'dpub': 'date(dt_published)'}).order_by('-dpub', '-views', '-dt_written', 'headline')[0:5]
Для сравнения скоростей исполнения нормального запроса и этого я провел следующие запросы MySQL:
SELECT *, date(dt_published) as dpub FROM `news_entry` order by dpub DESC LIMIT 500
# Showing rows 0 - 29 (500 total, Query took 0.1386 sec)
-
SELECT * , DATE( dt_published ) AS dpub FROM `news_entry` ORDER BY id DESC LIMIT 500
# Showing rows 0 - 29 (500 total, Query took 0.0021 sec) [id: 58079 - 57580]
Как вы можете видеть, нормальный запрос намного быстрее. Есть ли способ ускорить это?
Можно ли использовать вид MySQL с Django?
Я понимаю, что могу просто разделить поле DateTime на два поля (дата и время), но мне любопытно.
Структура:
CREATE TABLE IF NOT EXISTS `news_entry` (
`id` int(11) NOT NULL DEFAULT '0',
`views` int(11) NOT NULL,
`user_views` int(11) NOT NULL,
`old_id` int(11) DEFAULT NULL,
`type` varchar(1) NOT NULL,
`headline` varchar(256) NOT NULL,
`subheadline` varchar(256) NOT NULL,
`slug` varchar(50) NOT NULL,
`category_id` int(11) DEFAULT NULL,
`is_public` tinyint(1) NOT NULL,
`is_featured` tinyint(1) NOT NULL,
`dt_written` datetime DEFAULT NULL,
`dt_modified` datetime DEFAULT NULL,
`dt_published` datetime DEFAULT NULL,
`author_id` int(11) DEFAULT NULL,
`author_alt` varchar(256) NOT NULL,
`email_alt` varchar(256) NOT NULL,
`tags` varchar(255) NOT NULL,
`content` longtext NOT NULL
) ENGINE=MyISAM DEFAULT;
Решение
SELECT *, date(dt_published) as dpub FROM `news_entry` order by dpub DESC LIMIT 500
Этот запрос заказы на dpub
, хотя этот:
SELECT * , DATE( dt_published ) AS dpub FROM `news_entry` ORDER BY id DESC LIMIT 500
заказы на id
.
С id
скорее всего, PRIMARY KEY
для вашего стола, и каждый PRIMARY KEY
имеет неявный индекс, поддерживающий его, ORDER BY
Не нужно сортировать.
dpub
это вычисленное поле и MySQL
Не поддерживает индексы на вычисленных полях. Однако, ORDER BY dt_published
является ORDER BY dpub
также.
Вам нужно изменить ваш запрос к этому:
SELECT *, date(dt_published) as dpub FROM `news_entry` order by date_published DESC LIMIT 500
и создать индекс на news_entry (dt_published)
.
Обновлять:
С DATE
Монотонная функция, вы можете использовать этот трюк:
SELECT *, DATE(dt_published) AS dpub
FROM news_entry
WHERE dt_published >=
(
SELECT md
FROM (
SELECT DATE(dt_published) AS md
FROM news_entry
ORDER BY
dt_published DESC
LIMIT 499, 1
) q
UNION ALL
SELECT DATE(MIN(dt_published))
FROM news_entry
LIMIT 1
)
ORDER BY
dpub DESC, views DESC, dt_written DESC, headline
LIMIT 500
Этот запрос делает следующее:
Выбирает
500th
записывать внутрьdt_published DESC
заказ, или первая запись, опубликованная, должна быть меньше, чем500
Записи в таблице.Извлекает все записи, опубликованные позже, чем Дата последней выбранной записи. С
DATE(x)
всегда меньше или равноx
, там может быть больше, чем500
Записи, но все же намного меньше, чем весь стол.Заказы и ограничивает эти записи в зависимости от ситуации.
Вы можете найти эту статью интересную, так как она охватывает аналогичную проблему:
Другие советы
Может понадобиться индекс на dt_published
. Отказ Не могли бы вы опубликовать планы запроса на два запроса?