IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Requêtes MySQL Discussion :

Optimisation d'une requête de sélection [MySQL-5.7]


Sujet :

Requêtes MySQL

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2018
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Cantal (Auvergne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2018
    Messages : 6
    Points : 3
    Points
    3
    Par défaut Optimisation d'une requête de sélection
    Bonsoir tout le monde,

    Ayant cherché sur tout les forums, je fais appelle aux pro du sql (mysql ) de celui ci pour résoudre mon problème !
    J'essaie de faire un système de réservation d'hôtels en ligne. L'idée est que la requête retourne non seulement les hôtels mais aussi les chambres demandées par l'utilisateur. C'est à dire que si un utilisateur demande 3 chambres comme suit :

    chambre_1 : 2 adultes et 1 enfant
    chambre_2 : 1 adulte et 0 enfant
    chambre_3 : 2 adulte et 0 enfant

    Le résultat doit être comme suit :

    Hotel_1 : ( nom , ville , adresse , ...)
    - chambre 1 : adulte >=2 et enfant >=1 (categorie,vue,prix,max adult, max enfant)
    - chambre 2 : adulte >=1 et enfant >=0 (categorie,vue,prix,max adult, max enfant)
    - chambre 3 : adulte >=2 et enfant >=0 (categorie,vue,prix,max adult, max enfant)

    Hotel_2 : ( nom , ville , adresse , ...)
    - chambre 1 : adulte >=2 et enfant >=1 (categorie,vue,prix,max adult, max enfant)
    - chambre 2 : adulte >=1 et enfant >=0 (categorie,vue,prix,max adult, max enfant)
    - chambre 3 : adulte >=2 et enfant >=0 (categorie,vue,prix,max adult, max enfant)

    ....

    Ma base de donnée est constitué en gros comme ceci :

    la table hotel ( id , name , city , address , ....)
    la table room_category ( id , hotel_id , name , image , ...)
    la table room ( id , hotel_id , room_category_id , adult , child , prix ....)
    la table availability ( id , room_id , a_start, a_end )
    la table booked_room (id, room_id , b_start , b_end)

    Ma requête actuelle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
     
    SELECT h.*, r_1.*, rc_1.*,r_2.*,rc_2.*,r_3.*,rc_3.* 
     
    FROM hotel h 
    INNER JOIN room r_1 ON h.id = r_1.hotel_id 
    LEFT JOIN room_category rc_1 ON r_1.room_category_id = rc_1.id 
    LEFT JOIN availability a_1 ON r_1.id = a_1.room_id 
    LEFT JOIN booked_room br_1 ON r_1.id = br_1.room_id 
     
    INNER JOIN room r_2 ON h.id = r_2.hotel_id AND (r_1.id <> r_2.id) 
    LEFT JOIN room_category rc_2 ON r_2.room_category_id = rc_2.id 
    LEFT JOIN availability a_2 ON r_2.id = a_2.room_id 
    LEFT JOIN booked_room br_2 ON r_2.id = br_2.room_id 
     
    INNER JOIN room r_3 ON h.id = r_3.hotel_id AND (r_1.id <> r_2.id AND r_1.id <> r_3.id AND r_2.id <> r_3.id) 
    LEFT JOIN room_category rc_3 ON r_3.room_category_id = rc_3.id 
    LEFT JOIN availability a_3 ON r_3.id = a_3.room_id 
    LEFT JOIN booked_room br_3 ON r_3.id = br_3.room_id 
     
    WHERE 
     
    	r_1.adult >= 2 AND r_1.child >= 1 
    AND r_2.adult >= 1 AND r_2.child >= 0 
    AND r_3.adult >= 2 AND r_3.child >= 0  
     
     
    AND '2018-11-26' BETWEEN a_1.a_start AND a_1.a_end 
    AND '2018-12-20' BETWEEN a_1.a_start AND a_1.a_end 
    AND '2018-11-26' NOT BETWEEN br_1.b_start AND br_1.b_end 
    AND '2018-12-20' NOT BETWEEN br_1.b_start AND br_1.b_end 
     
    AND '2018-11-26' BETWEEN a_2.a_start AND a_2.a_end 
    AND '2018-12-20' BETWEEN a_2.a_start AND a_2.a_end 
    AND '2018-11-26' NOT BETWEEN br_2.b_start AND br_2.b_end 
    AND '2018-12-20' NOT BETWEEN br_2.b_start AND br_2.b_end 
     
    AND '2018-11-26' BETWEEN a_3.a_start AND a_3.a_end 
    AND '2018-12-20' BETWEEN a_3.a_start AND a_3.a_end 
    AND '2018-11-26' NOT BETWEEN br_3.b_start AND br_3.b_end 
    AND '2018-12-20' NOT BETWEEN br_3.b_start AND br_3.b_end 
    GROUP BY h.id
    ;
    Cette requête me retourne bien le résultat mais inutile de vous dire qu'elle prend du temps déjà avec 400 hôtels, énormément de temps !
    Donc svp si quelqu'un a une solution ou une idée de comment optimiser tout ça, ça serait vraiment top !

    Merci beaucoup.

  2. #2
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 127
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 127
    Points : 38 510
    Points
    38 510
    Billets dans le blog
    9
    Par défaut
    Bonjour

    Concernant vos tables, il y a des choses incohérentes qui expliquent au moins en partie les difficultés à requêter :

    • Il semble que la table "room_category" ne possède pas l'identifiant de la chambre, c'est incohérent, ou alors il s'agit d'une catégorie d'hotel
    • la table "availability", si elle est sensée servir à identifier les chambres disponibles, alors c'est une erreur de conception, une chambre est disponible s'il n'y a pas de réservation pour la période considérée
    • vous n'avez modélisé aucune table pour les clients, c'est très curieux
    • dans la même logique, la table des réservations ne connait pas d'identifiant client, toujours très curieux


    Par ailleurs, si vous aviez modélisé vos tables avec un logiciel ad-hoc et que vous aviez utilisé des préfixes de noms de colonnes, la compréhension des FK serait beaucoup plus aisée.
    Exemple. Pour la table HOTEL, si je décide d'utiliser le préfixe HO, alors mes colonnes sont (HO_id, HO_nom etc...) et dans la table CHAMBRE la FK permettant de connaitre l'hotel dans lequel elle se situe est HO_id, soit le même nom que dans la table HOTEL. Voilà qui évite de se poser des questions sur les FK

    Voici un exemple de MCD assez simple pour votre besoin, il est réalisé avec DB-MAIN logiciel gratuit :

    Pièce jointe 417901


    J'ai utilisé l'identification relative pour la chambre : l'identifiant primaire de la chambre est donc ID_hotel + ID_chambre.
    En effet, la chambre ne saurait exister sans son hôtel. C'est ce qu'on appelle une "entité-type faible". Si l’hôtel disparait, la chambre aussi.
    Pour la même raison, l'identification relative a été également utilisée coté réservations : une réservation n'existe que si le client existe, plus de client, plus de réservation.
    L'identifiant primaire de la réservation est donc ID_client + ID_réservation

    Voici le MLD généré par DB-MAIN à partir du MCD qui précède :

    Pièce jointe 417898

    Note : si votre application est développée par des équipes francophones, il n'y a rien à gagner à utiliser des termes anglais (room, booked etc.). Faites simple !

  3. #3
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2018
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Cantal (Auvergne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2018
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    Bonjour escartefigue,

    Merci de m'avoir lu

    Il semble que la table "room_category" ne possède pas l'identifiant de la chambre, c'est incohérent, ou alors il s'agit d'une catégorie d'hotel
    Effectivement, chaque hôtel à ses catégories de chambre, et chaque catégorie regroupe plusieurs chambres d'où le "room_category_id" dans la table "room"
    la table "availability", si elle est sensée servir à identifier les chambres disponibles, alors c'est une erreur de conception, une chambre est disponible s'il n'y a pas de réservation pour la période considérée
    En fait, la disponibilité de chaque chambre est limitée dans le temps. Une chambre peut être donc disponible juste du 01-11-2018 au 20-11-2018 ( et ça se fera manuellement dans l'admin). Je dois donc vérifier si les dates entrées par l'utilisateur sont dans cet intervalle puis vérifier s'il n'y a pas de réservations dans cette période dans la table (booked_room).
    vous n'avez modélisé aucune table pour les clients, c'est très curieux
    dans la même logique, la table des réservations ne connait pas d'identifiant client, toujours très curieux
    Y a bien une table "Guest" ( encore de l'anglais ) mais par soucis de simplification je n'ai pas mis toutes les tables ni tous les champs de tables. Je pensais que le problème venais de la façon dont la requête est construite, surtout le nombre important des jointures !

    Je ne sais pas si j'ai bien modélisé ma base mais j'espère que vous avez compris l'idée de ce que je souhaite faire. Vous avez raison, j'aurais dû accompagner ma question d'un schéma de ma base. Je ne connais pas le logiciel mais je vais l'essayer.



    Pour les préfixes et fk, j'utilse le framework symfony qui génère les tables d'après les entités, c'est donc généré automatiquement.

    il n'y a rien à gagner à utiliser des termes anglais (room, booked etc.). Faites simple !
    c'est pas pour me compliquer les choses mais c'est que dans plusieurs tutoriels c'est souvent de l'anglais qui est conseillé même dans les tutoriels en français d'ailleurs. En fin je croyais bien faire

  4. #4
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 127
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 127
    Points : 38 510
    Points
    38 510
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par YamEl Voir le message
    Je ne connais pas le logiciel mais je vais l'essayer.
    En gratuit il existe également JMerise qui a été grandement amélioré récemment


    Citation Envoyé par YamEl Voir le message
    c'est pas pour me compliquer les choses mais c'est que dans plusieurs tutoriels c'est souvent de l'anglais qui est conseillé même dans les tutoriels en français d'ailleurs. En fin je croyais bien faire
    L'un des inconvénients de l'anglais, outre le fait qu'il n'est pas forcément maitrisé par tous, est que les colonnes risquent encore plus d'avoir des noms réservés SQL, puisque tous les mots SQL sont de l'anglais.
    Et dans ce cas il faut encadrer les noms d'objets (tables, vues, colonnes...) de quotes inversées, c'est lourdingue à l'usage
    Problème évité si l'on utilise les préfixes (ou suffixes) dans les noms d'objets


    Vu que votre question initiale concernait les perfs, sachez que l'identification relative est propice aux performances

  5. #5
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2018
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Cantal (Auvergne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2018
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    Malheureusement, ni les suffixes ni préfixes ne résolvent mon problème mais c'est toujours bon à savoir, une chose de plus apprise aujourd'hui. Merci escartefigue

  6. #6
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 377
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 377
    Points : 19 049
    Points
    19 049
    Par défaut
    Salut YamEl.

    Citation Envoyé par YamEl
    C'est à dire que si un utilisateur demande 3 chambres comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    chambre_1 : 2 adultes et 1 enfant
    chambre_2 : 1 adultes et 0 enfant
    chambre_3 : 2 adultes et 0 enfant
    1) Je ne comprends pas trop votre logique.
    Vous n'allez pas me faire croire que vous avez une requête pour chaque configuration demandée par un utilisateur ?
    Dans votre exemple, vous extrayez que trois chambres.
    Et si une entreprise vous demande cinquante chambres, allez-vous nous créer une requête avec cinquante jointures ?
    Je comprends l'origine de votre problème de performance !

    Qu'est-ce qu'une chambre avec enfants ?
    Et qu'est-ce qu'un enfant ? Moins de 5 ans ? Moins de 10 ans ?
    Normalement dans un hotel, l'enfant est considéré comme l'ajout d'un petit lit supplémentaire.
    Existe-t-il des chambres où le lit enfant est déjà prévu et non déplacable ?

    2) ne mettez pas des "*" partout.
    Prenez seulement les colonnes dont vous avez besoin pour votre requête.

    3) le panachage entre des "inner join" et des "left outer join" risque de vous produire des résultats inatendus.
    Le mieux aurait été de tout mettre en "inner join" !

    4) avez-vous mis des index sur les colonnes qui sont utilisées comme jointure ?
    par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    INNER JOIN  room r_1
            ON  h.id = r_1.hotel_id
    r_1.hotel_id, est-ce une primary key ou pas ?

    5) avez-vous mis des index sur vos colonnes date :
    --> a_start
    --> a_end
    --> b_start
    --> b_end

    6) si vous avez mis des index, comment ont-ils été écrits ?

    7) pourquoi avoir répété trois fois le bloc suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    INNER JOIN  room r_1
            ON  h.id = r_1.hotel_id
     
    LEFT JOIN  room_category rc_1
           ON  r_1.room_category_id = rc_1.id
     
    LEFT JOIN  availability a_1
           ON  r_1.id = a_1.room_id
     
    LEFT JOIN  booked_room br_1
           ON r_1.id = br_1.room_id
    ca ne sert à rien, sauf si vous avez une raison valable de faire de la présentation.
    Au lieu d'avoir trois lignes distincts, une seule ligne mais avec trois groupes de colonnes.
    C'est une des raisons de votre problème de performance.

    J'ai bien compris que vos trois sous-requêtes sont exclusives.
    D'autant que vos conditions d'extractions sont inclusives :

    (adulte >= 2 et enfant >=1) est inclue dans (adulte >= 2 et enfant >=0) qui est aussi inclue dans (adulte >= 1 et enfant >=0).

    8) Pourquoi mettre ces conditions dans un where ?
    Vous cherchez à extraire que les lignes qui vous intéresse.
    Pourquoi tout récupérer, puis ensuite les éliminer ?
    Autant les éliminer d'abord en les mettant dans vos jointures, comme ci-après :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    INNER JOIN  room r_1
            ON  r_1.hotel_id  = h.id
           AND  r_1.adult    >= 2
           AND  r_1.child    >= 1
    7) même remarque pour :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      AND '2018-11-26'     BETWEEN  a_1.a_start AND  a_1.a_end
      AND '2018-12-20'     BETWEEN  a_1.a_start AND  a_1.a_end
    qui va devenir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    INNER JOIN  availability a_1
            ON  a_1.room_id   = r_1.id
           AND  a_1.a_start  >= '2018-11-26'
           AND  a_1.a_end    <= '2018-12-20'
    8) idem pour :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      AND '2018-11-26' NOT BETWEEN br_1.b_start AND br_1.b_end
      AND '2018-12-20' NOT BETWEEN br_1.b_start AND br_1.b_end
    qui va devenir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    INNER JOIN  booked_room br_1
            ON  br_1.room_id  = r_1.id
           AND  br_1.b_start >= '2018-11-26'
           AND  br_1.b_end   <= '2018-12-20'
    9) revoir votre base de données car la modélisation ne se prête pas à ce que vous cherchez à faire.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  7. #7
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2018
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Cantal (Auvergne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2018
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    Bonsoir Artemus24
    Citation Envoyé par Artemus24 Voir le message

    1) Je ne comprends pas trop votre logique.
    Vous n'allez pas me faire croire que vous avez une requête pour chaque configuration demandée par un utilisateur ?
    Bien-sûr que non, la requête est construite avec une Class en fonction des paramètres de l'utilisateur (les dates, le nombre de chambre, la capacité de chaque chambre...) . là c'est juste pour l'exemple.
    Qu'est-ce qu'une chambre avec enfants ?
    Et qu'est-ce qu'un enfant ? Moins de 5 ans ? Moins de 10 ans ?
    Normalement dans un hotel, l'enfant est considéré comme l'ajout d'un petit lit supplémentaire.
    Existe-t-il des chambres où le lit enfant est déjà prévu et non déplacable ?
    Enfant c'est moins de 17 ans, et qui n'a pas le droit de réserver une chambre s'il n'est pas accompagné d'un adulte dont la chambre sera justement réservée au nom de celui-ci (l'adulte) Et dans les contrats avec les hôtels on parle de capacité d'une chambre. c'est à dire qu'une chambre pourrait par exemple recevoir au maximum 2 adultes et 1 enfant (-17 ans ) et à ce stade là on a pas à savoir si la chambre dispose d'un grand lit (double) et d'un lit simple ou bien de 3 lits simples.

    Pour les autres questions, je suis un peu en train d'essayer tout et n'importe quoi. Et c'est vraiment pas facile de s'y retrouver !

    j'ai fait une capture d'écran de ma base de donnée avec un logiciel et voilà ce que ça a donnée :
    Nom : CaptureBaseDeDonnées.PNG
Affichages : 252
Taille : 67,1 Ko

    et voici les requête que j'ai récupéré depuis phpMyAdmin :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
     
    --
    -- Structure de la table `availability`
    --
     
    DROP TABLE IF EXISTS `availability`;
    CREATE TABLE IF NOT EXISTS `availability` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `a_start` date NOT NULL,
      `a_end` date NOT NULL,
      `room_id` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `IDX_3FB7A2BF54177093` (`room_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=9986 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
     
     
     
     
    --
    -- Structure de la table `booked_room`
    --
     
    DROP TABLE IF EXISTS `booked_room`;
    CREATE TABLE IF NOT EXISTS `booked_room` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `room_id` int(11) NOT NULL,
      `b_start` date NOT NULL,
      `b_end` date NOT NULL,
      PRIMARY KEY (`id`),
      KEY `IDX_EEFBCBE354177093` (`room_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=12210 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
     
     
    --
    -- Structure de la table `category_name`
    --
     
    DROP TABLE IF EXISTS `category_name`;
    CREATE TABLE IF NOT EXISTS `category_name` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
     
    --
    -- Structure de la table `hotel`
    --
     
    DROP TABLE IF EXISTS `hotel`;
    CREATE TABLE IF NOT EXISTS `hotel` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
      `wilaya` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
      `city` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
      `adress` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
      `pc` varchar(15) COLLATE utf8mb4_unicode_ci NOT NULL,
      `phone` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
      `mail` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
      `website` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
      `image` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=401 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
     
    --
    -- Structure de la table `room`
    --
     
    DROP TABLE IF EXISTS `room`;
    CREATE TABLE IF NOT EXISTS `room` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `view` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
      `bathroom` tinyint(1) NOT NULL,
      `hotel_id` int(11) NOT NULL,
      `room_category_id` int(11) NOT NULL,
      `adult` smallint(6) NOT NULL,
      `child` smallint(6) NOT NULL,
      PRIMARY KEY (`id`),
      KEY `IDX_729F519B3243BB18` (`hotel_id`),
      KEY `IDX_729F519B67333DD` (`room_category_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=6701 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
     
     
    --
    -- Structure de la table `room_category`
    --
     
    DROP TABLE IF EXISTS `room_category`;
    CREATE TABLE IF NOT EXISTS `room_category` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `image` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
      `hotel_id` int(11) DEFAULT NULL,
      `name_id` int(11) NOT NULL,
      PRIMARY KEY (`id`),
      KEY `IDX_A6AAD9053243BB18` (`hotel_id`),
      KEY `IDX_A6AAD90571179CD6` (`name_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1601 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
     
     
    --
    -- Contraintes pour la table `availability`
    --
    ALTER TABLE `availability`
      ADD CONSTRAINT `FK_3FB7A2BF54177093` FOREIGN KEY (`room_id`) REFERENCES `room` (`id`);
     
    --
    -- Contraintes pour la table `booked_room`
    --
    ALTER TABLE `booked_room`
      ADD CONSTRAINT `FK_EEFBCBE354177093` FOREIGN KEY (`room_id`) REFERENCES `room` (`id`);
     
    --
    -- Contraintes pour la table `room`
    --
    ALTER TABLE `room`
      ADD CONSTRAINT `FK_729F519B3243BB18` FOREIGN KEY (`hotel_id`) REFERENCES `hotel` (`id`),
      ADD CONSTRAINT `FK_729F519B67333DD` FOREIGN KEY (`room_category_id`) REFERENCES `room_category` (`id`);
     
    --
    -- Contraintes pour la table `room_category`
    --
    ALTER TABLE `room_category`
      ADD CONSTRAINT `FK_A6AAD9053243BB18` FOREIGN KEY (`hotel_id`) REFERENCES `hotel` (`id`),
      ADD CONSTRAINT `FK_A6AAD90571179CD6` FOREIGN KEY (`name_id`) REFERENCES `category_name` (`id`);
    voilà, s'il y a quelque à refaire je suis tout oui !

    Merci à vous.

  8. #8
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Reprenez le modèle proposé par Esacrtefigue dans son message #2 !

    Et pour bien faire, vous devriez avoir une table calendrier et une table associative contenant les jours ou périodes de fermeture de l'hôtel. Certains hôtels peuvent en effet être fermés le dimanche ou un autre jour, voire pendant une période (hôtels ouverts seulement pendant la saison touristique).
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  9. #9
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 377
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 377
    Points : 19 049
    Points
    19 049
    Par défaut
    Salut YamEl.

    Suivez les bons conseils d'Escartefigue en ce qui concerne la modélisation de votre base de données.

    A partir d'une bonne modélisation, on peut envisager la requête que vous cherchez à faire.
    La difficulté est de pouvoir traiter, dans une seule requête, des demandes multiples.
    Il se trouve que vos trois demandes sont inclusives, ce qui vous oblige à les exclure mutuellement afin de ne pas avoir de la redondance.

    Je pense que vous devez simplifier la demande que votre utilisateur fait :
    Citation Envoyé par YamEl
    un utilisateur demande 3 chambres comme suit :

    chambre_1 : 2 adultes et 1 enfant
    chambre_2 : 1 adulte et 0 enfant
    chambre_3 : 2 adulte et 0 enfant
    Pourquoi faire cela en une seule demande ?

    Citation Envoyé par YamEl
    Enfant c'est moins de 17 ans
    Ce n'est plus un enfant mais un adolescent qui utilisera un lit comme un adulte.

    Citation Envoyé par YamEl
    Et dans les contrats avec les hôtels on parle de capacité d'une chambre.
    Oui, je le sais, sauf que dans certains hôtels, un couple avec enfant (en bas âge), va réserver une chambre avec deux lits ou un lit double.
    L’hôtel mettra à leur disposition un lit pliant pour l'enfant.
    Pour un adolescent, c'est un lit d'adulte qui lui faut.

    Ma remarque concernait la justification de l'enfant dans la réservation d'une chambre.
    Ne serait-il pas plus simple de formuler la demande de trois chambres pour six personnes ?

    Autrement dit, doit-on faire une et une seule réservation pour trois chambres, ou bien trois réservations d'une seule chambre ?
    A vouloir traiter des cas tordues, il serait mieux de simplifier votre demande, quitte à la traiter plusieurs fois.
    Cela aura un impact très favorable sur la performance.

    Par exemple, pour la première demande (2 adultes + 1 enfant) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    select         *
             from  hotel         as h
     
       inner join  room          as r
               on  r.hotel_id =  h.id
              and  r.adult    >= 2
              and  r.child    >= 1
     
       inner join  room_category as c
               on  c.id       = r.room_category_id
     
       inner join  availability  as a
               on  a.room_id  =  r.id
              and  a.start    <= '2018-11-26'
              and  a.end      >= '2018-12-20'
     
       inner join  booked_room   as b
               on  a.room_id  =  r.id
              and  b.start    <= '2018-11-26'
              and  b.end      >= '2018-12-20'
     
    group by  h.id;
    Quand cette première demande est validée, vous avez déjà une réservation disons partielle, qui va être exclure automatiquement des demandes suivantes.
    Vous n'avez plus qu'à formuler vos autres demandes, pour finaliser la réservation définitive.
    Et si vous n'arrivez pas à finaliser la demande, il vous suffit alors d'annuler les réservations qui ont déjà été faites.
    A vouloir tout faire en même temps, vous complexifiez le travail en pénalisant les performances.
    Juste une remarque concernant la table "room_category" ? A quoi vous sert-elle dans la requête ?

    Je pense que vous devez aussi repenser à l'ergonomie de l'utilisateur face aux demandes multiples.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  10. #10
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2018
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Cantal (Auvergne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2018
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    Bonjour tout le monde,

    Je vous remercie tous pour vos réponses, vos remarques et vos conseils.

    En vous lisant tous, je conclu que ma base de données est nulle
    Mais en regardant ma base, je vois qu'elle diffère peu de celle proposée par Esacrtefigue. En effet dans mon schéma la table "catégorie" est en relation avec "hotel" et "chambre", alors que dans celle de Esacrtefigue elle est juste en relation avec "chambre".
    Mais même sans "catégorie" la requête reste la même pour mon besoin.
    Maintenant, supposons le schéma de Esacrtefigue, et supposons que je veuille récupérer les hotels qui ont au moins ces 3 chambres libres càd

    - au moins une chambre qui pourrait accueillir 2 adultes et 1 enfant;
    - au moins une chambre qui pourrait accueillir 1 adulte
    - au moins une chambre qui pourrait accueillir 2 adultes

    Comment interpréter cette demande en sql ?

    Citation Envoyé par CinePhil Voir le message
    Et pour bien faire, vous devriez avoir une table calendrier et une table associative contenant les jours ou périodes de fermeture de l'hôtel. Certains hôtels peuvent en effet être fermés le dimanche ou un autre jour, voire pendant une période (hôtels ouverts seulement pendant la saison touristique).
    Exactement ! mais j'en suis pas encore là. Pas avant d'avoir trouvé une solution à cette requête

    Citation Envoyé par Artemus24 Voir le message

    Ma remarque concernait la justification de l'enfant dans la réservation d'une chambre.
    Ne serait-il pas plus simple de formuler la demande de trois chambres pour six personnes ?
    Salut Artemus24,

    Parce que :
    1 - Y a des chambres qui ne pourront pas accueillir d'enfant, carrément ! par exemple, dans un même hôtel, une chambre double pourrait accueillir un enfant et une autre ( double aussi ) non !
    2 - les pension pour un enfant sont moins chères que celle d'un adulte et donc j'en aurais aussi besoin pour calculer le prix dans la réservation

    Citation Envoyé par Artemus24 Voir le message

    Ne serait-il pas plus simple de formuler la demande de trois chambres pour six personnes ?

    Autrement dit, doit-on faire une et une seule réservation pour trois chambres, ou bien trois réservations d'une seule chambre ?
    3 chambres pour six personnes ? comment ?

    Oui une seule réservation pour les trois chambres. dans une réservation apparaîtra le nom de celui qui a réservé et les nom du responsable (adulte) pour chaque chambre

  11. #11
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 377
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 377
    Points : 19 049
    Points
    19 049
    Par défaut
    Salut YamEl.

    Selon moi, le plus simple est de faire une requête par demande.
    A chaque demande, le résultat est stocké temporairement dans la réservation en cours.
    Autrement dit, une réservation peut contenir plusieurs demandes.

    A la deuxième demande, sachant que l'on vient de faire une première demande, celle-ci sera automatiquement exclue (la première demande) car potentiellement en cours de réservation.
    Du coup, cela simplifie grandement votre requête et sa performance.

    Idem à la troisième demande.

    Et si chaque demande est conforme à ce que le client désire, alors il suffit de valider votre réservation temporaire en réservation définitive.

    Et dans cette approche, la table "reservation" à son rôle à jouer puisqu'elle élimine les demandes temporaires déjà faites.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  12. #12
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2018
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Cantal (Auvergne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Octobre 2018
    Messages : 6
    Points : 3
    Points
    3
    Par défaut
    Merci beaucoup Artemus24,

    J'ai préféré gardé ma base de données telle qu'elle est parce que j'en ai besoin comme ça. Mais j'ai réussi à baisser le temps de retour de ma requête en améliorant cette dernière. Ma question et c'est j'espère la dérnière, c'est est ce que 100 à 150 milisecondes c'est rapide pour une seule requête sachant qu'il y a + 4000 hotels +62000 chambres et des centaines de milliers voire un million de reservation ?

  13. #13
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 377
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 377
    Points : 19 049
    Points
    19 049
    Par défaut
    Salut YamEl.

    Citation Envoyé par YamEl
    Ma question et j'espère que c'est la dernière, 100 à 150 millisecondes est-ce rapide pour une seule requête ?
    Un utilisateur est positionné derrière son écran et tape sa requête.
    Si elle dure moins de 1 seconde, je trouve cela tout à fait correcte.

    Mais avez-vous tenu compte du temps réseau pour acheminer le résultat de votre requête à l'utilisateur distant ?

    Citation Envoyé par YamEl
    sachant qu'il y a + 4000 hôtels +62000 chambres et des centaines de milliers voire un million de réservation ?
    La rapidité de votre requête dépend en grande partie de l'organisation de vos données.
    L'usage des index permet d'améliorer la rapidité de votre requête.
    Ainsi que le nombre de jointures que vous êtes obligées de faire.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Optimisation d'une requête d'insertion
    Par fdraven dans le forum Oracle
    Réponses: 15
    Dernier message: 01/12/2005, 14h00
  2. Optimisation d'une requête patchwork
    Par ARRG dans le forum Langage SQL
    Réponses: 1
    Dernier message: 11/09/2005, 15h23
  3. Réponses: 1
    Dernier message: 03/08/2005, 11h41
  4. optimisation d'une requête avec jointure
    Par champijulie dans le forum PostgreSQL
    Réponses: 8
    Dernier message: 07/07/2005, 09h45
  5. [DB2] Optimisation d'une requête
    Par ahoyeau dans le forum DB2
    Réponses: 7
    Dernier message: 11/03/2005, 17h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo