web-dev-qa-db-fra.com

Quelles colonnes doivent être indexées lorsque toutes peuvent être utilisées dans différentes requêtes de recherche?

Contexte

Je travaille sur un site Web pour une chaîne de cinéma actuellement située dans quatre villes différentes (pourrait se développer à l'avenir). Ils utilisent le même site Web de base de données pour toutes les villes, ce qui signifie que je dois avoir une colonne dans certaines tables qui contiennent l'ID de la ville que chaque rangée appartient.

À l'heure actuelle, j'ai trois tables différentes:

  • Cinemas - contient le cinéma de chaque ville (identifiant et nom).
  • Movies - contient tous les films qui ont été/seront montrés au cinéma.
  • Showtimes - contient toutes les émissions pour tous les films dans toutes les villes.

La structure de la table Showtimes est la suivante:

Column Name   | Column Type  | Description
--------------+--------------+---------------
ID            | BIGINT       | (Primary) Unique ID for each showtime (perhaps unnecessary?)
CinemaID      | TINYINT      | Foreign key bound to Cinemas.ID
MovieID       | BIGINT       | Foreign key bound to Movies.ID
Showtime      | DATETIME     | At what date and time the movie will show 

(will contain multiple rows for each movie, i.e. one row for each showtime)

Comment cette table sera utilisée

Un utilisateur du site Web doit être capable de:

  • Affichez tous les films et les films actuels/à venir (triés par date) dans la ville sélectionnée.

    Exemple de requête (backend):

    SELECT MovieID, Showtime FROM Showtimes WHERE CinemaID = ? ORDER BY Showtime
    
  • Sélectionnez un seul film et affiché tous les viftimes pour ce titre spécifique uniquement (dans la ville sélectionnée).

    Exemple de requête:

    SELECT Showtime FROM Showtimes WHERE CinemaID = ? AND MovieID = ? ORDER BY Showtime
    
  • Sélectionnez une seule journée et affichez tous les films et affichés pour cette journée seulement (dans la ville sélectionnée).

    Exemple de requête:

    SELECT MovieID, Showtime FROM Showtimes WHERE CinemaID = ? AND (Showtime BETWEEN [date 12:00 AM] AND [date 12:00 PM])
    

Donc, naturellement, j'ai décidé que je devais créer des index pour les colonnes.

Problème

Ce que j'ai des problèmes, c'est décider/déterminer comment indexer les colonnes correctement. Un index pour chaque colonne semble assez cher[1][2] J'ai donc commencé à regarder dans des index composites, ce qui semble être le bon choix, mais a également conduit à encore plus de confusion.

De ma compréhension (sur la base de ce que j'ai lu), vous devez ajouter les colonnes à l'index par ordre de sélectivité, ce qui rend le plus sélectif (je suppose que signifie la plus unique/avec la plus cardinalité?) Colonne Le premier dans l'indice composite[3] (Dans mon cas, ce serait la colonne Showtime). Le seul problème avec c'est que l'index ne peut être utilisé que par la base de données que si la première colonne est incluse dans la requête de recherche.[4][5], ce qu'il n'est actuellement pas dans l'une ou l'autre de mes questions.

Question

Quel type d'index devrais-je appliquer à mes colonnes afin de couvrir tous les scénarios d'utilisation? (Le dernier scénario peut être omis, mais les deux premiers sont nécessaires)

Devrais-je utiliser un index composite sur toutes les colonnes, pour certaines colonnes ou ai-je besoin d'un index séparé pour chaque colonne?

Ce tableau est mis à jour au plus à quelques reprises par semaine pour ajouter de nouveaux spectacles.

Notes de bas de page

1index MySQL - quelles sont les meilleures pratiques?

2indexer chaque colonne d'une table

3Quelle est l'importance de l'ordre des colonnes dans les index? (Question)

4Quelle est l'importance de l'ordre des colonnes dans les index? (# 2 Réponse top-vote)

5Quand dois-je utiliser un index composite?

5
Visual Vincent
WHERE CinemaID = ? ORDER BY Showtime  -- and
WHERE CinemaID = ? AND (Showtime BETWEEN [date 12:00 AM] AND [date 12:00 PM])  -- need:
INDEX(CinemaID, Showtime)

WHERE CinemaID = ? AND MovieID = ? ORDER BY Showtime  -- needs:
INDEX(CinemaID, MovieId, Showtime)  -- or
INDEX(MovieId, CinemaID, Showtime)

En supposant que le triple (filmid, cinémail, showtime) est unique, je suggère de se débarrasser de id et d'avoir

PRIMARY KEY(CinemaID, MovieId, Showtime)
INDEX(CinemaID, Showtime)

Y a-t-il des cas où la partie principale du WHERE est MovieID=...?

Cinémas - une liste de chaque ville et son cinéma (identifiant et nom):

SELECT Cinema, CinemaID FROM Cimemas;  -- (no index needed)

Films - Une liste de films qui a été/seront montrés au cinéma.

SELECT DISTINCT MovieID FROM ShowTimes WHERE CinemaID=...
INDEX(CinemaID, MovieID)  -- already handled by my proposed PK

Showtimes - une liste de tous les spectacles pour tous les films dans toutes les villes. - Ceci est une énorme production; repenser l'exigence pour cela. C'est-à-dire que pensez à ce que le client fera avec cela.

La plupart de ces indices pourraient être déduites d'étudier Cookbook d'indexation et Indexation composite ) ==) ==

Notez comment je n'ai pas suggéré d'index (colonne unique VS Composite, plus des spécificités) jusqu'à ce que je sait le SELECTs.

"Colonnes à l'indice par ordre de sélectivité, rendant le plus sélectif (je suppose que signifie que le plus unique/avec la plus cardinalité?)" - Non. Sélectivité est non la clé pour la conception d'un indice composite. Commencez avec toutes les colonnes =, IN Toute ordre. (Mon livre de cuisine habite sur ce sujet.)

"L'index ne peut être utilisé que par la table si la première colonne est incluse dans la requête de recherche" - surtout vrai. Remarquez comment j'ai recommandé 2 index (rappelez-vous: le PK est un index). Il y a des cas où un index peut être utilisé pour GROUP BY ou ORDER BY, ignorant le WHERE; Mais ce sont rares.

"D'abord dans l'indice composite ... Showtime" - c'est Habituellement Contre-productif de mettre un DATETIME d'abord dans un index composite. En particulier, votre 3ème requête peut Utilisez les deux Colonnes de INDEX(CinemaID, Showtime), mais Pas à la fois Colonnes de INDEX(Showtime, CinemaID). Il est facile de voir ceci: pensez à écrire deux listes de cinémas et de shiftimes. Avoir une liste triée d'abord sur le cinéma (une fonction la INDEX(cinema, time); avoir l'autre trié à l'heure. Pensez à laquelle on aurait toutes les lignes pour un cinéma particulier sur une gamme de temps ("regroupée").

S'il y a aussi un ScreenID en raison de deux écrans montrant le même film en même temps, cliquez sur le PK. Cependant, tous les index devront repenser.

(Désolé, Willem, j'ai écrit ma réponse avant de lire le vôtre - nous disons presque les mêmes choses.)

5
Rick James

Vous optimisez pour la taille *, sur une table extrêmement petite. Étant donné que cela fondamentalement une table de pont, il n'a pas vraiment besoin d'une clé primaire, et même si c'était le cas, il n'aurait pas besoin d'être un Bigint, l'identifiant des films n'a pas besoin d'être une légèreté non plus. Si vous pensez avoir besoin de plus de quelques milliards de films, ensuite non signé, mais je pense qu'il est peu probable que vous alliez courir dans cette limitation pour le nombre de films à tout moment.

Avoir un index sur chacun de vos termes principaux, film, cinéma, showtime. Voyez quelles sont vos performances, et si c'est inacceptable, ajoutez des combinaisons d'index supplémentaires.

Après avoir essayé d'essayer sans index du tout (sauf éventuellement un pk sur une colonne Auto_inCremmentation utilisée comme clé de substitution) et une quantité raisonnable de données, disons 200 cinémas x (5 nouveaux films par semaine x 4 Afficher les temps quotidiens x 7 x (520 semaines alias 10 ans)) = 14 560 000 enregistrements et voyez comment cela fonctionne.

Franchement à cette taille, une table de table complète ne devrait pas être trop mauvaise.

Taille sage Un indice totalement couvert est de 13 octets, des tours jusqu'à 16,00 x 14 560 000/1024 sont de 227 500 000 AKA 227MB AKA .277. Times 4 pour la table et chacun de l'indice de couverture possible et nous sommes à près de 1,25 concert pour la table et les index. Notez que tous les index combinés auraient la même taille, ont simplement un poids différent pour les données ...

Notez que la façon de vous accélérer réellement, est de mettre vos données historiques dans une autre table ou d'utiliser un partitionnement. Dans ce cas si vous avez les données pour le mois à venir, il s'agit de 5 x 4 x 7 x 30 x 200 = 120 000 enregistrements et numériser 120k enregistrements ne doit pas être un problème. À ce stade, vous pourriez simplement garder tout cela en mémoire et utiliser un dictionnaire local pour regarder les choses.

Notez également que je suppose que vous éloignez-vous comme une folle, car vous n'avez actuellement qu'un seul écran, donc probablement seulement 4 à 6 enregistrements par jour par cinéma et un faible nombre de cinémas, donc un nombre quotidien plus réaliste est probablement compris entre 1k et 10K enregistrements par mois. Totalement possible, vous obtiendrez une performance suffisante décente si vous stockiez les valeurs dans une feuille de calcul Excel qui a été mise à jour manuellement quotidiennement.

PS Pour la sélectivité de l'index, vous ne voulez pas le plus précisé, vous voulez la plus grande couverture. Vous ne cherchez pas un seul disque, vous recherchez un groupe, ce qui signifie que vous souhaitez que l'index soit sur la colonne qui renvoie votre groupe. Cela signifie notamment que si vous souhaitez rechercher des films par jour, vous devez diviser la date et l'heure en deux colonnes afin que vous puissiez mettre un index à la date (et éventuellement un à l'heure).

* La raison pour laquelle j'ai dit que vous optimisiez pour l'espace, c'est parce que vous semblez être inquiet du coût de l'indice. Le coût d'un indice se présente sous deux formes, une insertion/la mise à jour plus lente/la mise à jour et de l'espace disque. Pour un index complet de couverture qui signifie fondamentalement que chaque index coûte autant que la table. Le temps d'ajouter une seule ligne à une table avec 16 octets (ou 24) est petit et non accumulant (c'est-à-dire essentiellement constant quel que soit le nombre de lignes). Alors que l'espace disque s'accumule lentement, il pousse.

1
jmoreno