acelerando las consultas MySQL / MySQL vistas en Django
-
01-10-2019 - |
Pregunta
Yo uso el siguiente código para seleccionar entradas de noticias populares (por fecha) de la base de datos:
popular = Entry.objects.filter(type='A', is_public=True).extra(select = {'dpub': 'date(dt_published)'}).order_by('-dpub', '-views', '-dt_written', 'headline')[0:5]
Para comparar las velocidades de ejecución de una consulta normal y éste me encontré con las siguientes consultas de 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]
Como se puede ver la consulta normal es mucho más rápido. ¿Hay una manera de acelerar este proceso?
¿Es posible utilizar las vistas de MySQL con Django?
Me doy cuenta de que sólo podía dividir el campo de fecha y hora en dos campos (fecha y hora), pero tengo curiosidad.
Estructura:
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;
Solución
SELECT *, date(dt_published) as dpub FROM `news_entry` order by dpub DESC LIMIT 500
Esta consulta órdenes en dpub
, mientras éste:
SELECT * , DATE( dt_published ) AS dpub FROM `news_entry` ORDER BY id DESC LIMIT 500
órdenes de id
.
Desde id
es más probablemente un PRIMARY KEY
para su mesa, y cada PRIMARY KEY
tiene un índice implícito respaldo que, ORDER BY
no tiene por qué tipo.
dpub
es un campo calculado y MySQL
no soporta índices en campos calculados. Sin embargo, ORDER BY dt_published
es un ORDER BY dpub
también.
Es necesario cambiar la consulta a esto:
SELECT *, date(dt_published) as dpub FROM `news_entry` order by date_published DESC LIMIT 500
y crear un índice en news_entry (dt_published)
.
Actualización:
Desde DATE
es una función monótona, es posible emplear este truco:
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
Esta consulta hace lo siguiente:
-
selecciona el registro
500th
con el findt_published DESC
, o el primer registro publicado no debe ser inferior a los registros500
en la tabla. -
Obtiene todos los registros enviado a más tardar el fecha del último registro seleccionado. Desde
DATE(x)
es siempre menor o igual ax
, no puede haber más de registros500
, pero aún mucho menos que toda la tabla. -
Órdenes y límites de estos registros según sea apropiado.
Usted puede encontrar este artículo interesante, ya que cubre un problema similar:
Otros consejos
posible que tenga un índice en dt_published
. Podría publicar los planes de consulta para las dos consultas?