excès de vitesse des requêtes mysql / mysql vues dans django
-
01-10-2019 - |
Question
J'utilise le code suivant pour sélectionner les entrées de nouvelles populaires (par date) de la base de données:
popular = Entry.objects.filter(type='A', is_public=True).extra(select = {'dpub': 'date(dt_published)'}).order_by('-dpub', '-views', '-dt_written', 'headline')[0:5]
Pour comparer les vitesses d'exécution d'une requête normale et celui-ci j'ai couru les requêtes MySQL suivantes:
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]
Comme vous pouvez le voir la requête normale est beaucoup plus rapide. Est-il un moyen d'accélérer ce?
Est-il possible d'utiliser des vues MySQL avec django?
Je me rends compte que je pouvais diviser le champ datetime en deux champs (date et heure), mais je suis curieux.
Structure:
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;
La solution
SELECT *, date(dt_published) as dpub FROM `news_entry` order by dpub DESC LIMIT 500
ORDONNE de requête sur dpub
, alors que celui-ci:
SELECT * , DATE( dt_published ) AS dpub FROM `news_entry` ORDER BY id DESC LIMIT 500
commandes sur id
.
Depuis id
est très probablement un PRIMARY KEY
pour votre table, et chaque PRIMARY KEY
a un indice implicite le soutenir, ORDER BY
n'a pas besoin de trier.
dpub
est un champ et MySQL
calculé ne prend pas en charge les index sur les champs calculés. Cependant, ORDER BY dt_published
est un ORDER BY dpub
aussi bien.
Vous devez changer votre requête à ceci:
SELECT *, date(dt_published) as dpub FROM `news_entry` order by date_published DESC LIMIT 500
et créer un index sur news_entry (dt_published)
.
Mise à jour:
Depuis DATE
est une fonction monotone, vous pouvez employer cette astuce:
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
Cette requête effectue les opérations suivantes:
-
Sélectionne le dossier de
500th
afin dedt_published DESC
, ou le premier enregistrement posté devrait y avoir moins de dossiers de500
dans le tableau. -
Récupère tous les enregistrements affichés plus tard le date du dernier enregistrement sélectionné. Depuis
DATE(x)
est toujours inférieure ou égale àx
, il peut y avoir plus de dossiers de500
, mais toujours beaucoup moins que la table. -
Les commandes et les limites de ces dossiers, selon le cas.
Vous pouvez trouver cet article intéressant, car il couvre un problème similaire:
Autres conseils
mai besoin d'un index sur dt_published
. Pourriez-vous afficher les plans de requête pour les deux requêtes?