2
votes

Optimiser cette requête pour 1000 patients dans la table des patients

Quelle est la meilleure solution pour optimiser cette requête pour 1 000 patients dans le tableau des patients:

SELECT patientid,firstname,lastname,mobilephone,email,
       Format(Coalesce((SELECT Sum(ammount) - Sum(( ammount * ( discount / 100 )))
FROM   invoice
WHERE  invoice.patientid = patient.patientid
       AND invoicednumber > 0) - (SELECT Sum(ammount) FROM payment WHERE payment.patientid = patient.patientid), 0), 0) AS answer,
       Date_format((SELECT Max(paymentdate) FROM payment WHERE  payment.patientid = patient.patientid), '%d-%m-%Y')
       AS
       lastpaymentdate
FROM   patient
WHERE  1 

Tableau des patients:
Tableau des patients http://sqlfiddle.com/#!9/40945d/2/0 Tableau des factures:
Tableau de facturation Tableau de paiement:
Tableau des paiements Données de résultat:
Result Data

cela prend 10 secondes sur Amazon EC2 t2.micro

Voici l'exemple du violon sql:
Voici l'exemple de violon sql http://sqlfiddle.com/#!9/40945d/ 2/0


9 commentaires

La première étape ici consiste à formater votre question afin qu’elle soit lisible. Veuillez ajouter quatre espaces ou plus à chaque ligne de la requête, afin qu'elle apparaisse sous forme de code à espacement fixe.


mis à jour, merci


Je l'ai un peu modifié, mais ce n'est pas vraiment faisable. Veuillez ajouter quelques exemples de données avec un résultat souhaité, car je pense que vous recherchez des jointures


Ce que je recherche, c'est d'obtenir la «réponse» d'équilibre, pour chaque patient de la table des patients. le blance se compose de la somme des factures et de la somme des remises moins la somme du paiement


Votre requête est illisible. Je m'interroge depuis quelques minutes, je ne peux pas décider quelles colonnes appartiennent à où. Veuillez ajouter une table de démonstration avec 1 patient et quelques chiffres. Je pense que vous devez refaire toute cette requête.


mis à jour, merci pour votre aide


mis à jour avec le lien de violon sql, merci


le violon SQL est-il juste un échantillon ou copié à partir de votre schéma de base de données actuel?


C'est un exemple de mon schéma de base de données actuel


3 Réponses :


1
votes
SELECT patientid, firstname,lastname,mobilephone,email, FORMAT( COALESCE(
    ( SELECT SUM(ammount)-SUM((ammount * (discount/100))) 
    FROM invoice 
    INNER JOIN patient
    ON invoice.patientid = patient.patientid 
    and invoicednumber >0) - 
    ( SELECT SUM(ammount) 
      FROM payment 
      INNER JOIN patient 
      ON payment.patientid = patient.patientid ),0),0) AS answer, 
    DATE_FORMAT(( SELECT max(paymentdate) 
                  FROM payment 
                  INNER JOIN patient 
                  ON payment.patientid = patient.patientid ),'%d-%m-%Y') As lastpaymentdate 
from patient WHERE 1 
This will work more faster!!!!  Try it and let me know  UPDATE
I have replace WHERE clause with inner join which will help to get data in quick time.
I would also add that if indexes are not there on primary key then do add.  

3 commentaires

Veuillez expliquer ce que vous avez fait et pourquoi vous l'avez fait. SO n'est pas un type de site "voici la réponse", mais plutôt "voici comment je suis arrivé à cette réponse"


Merci pour votre réponse, mais la réponse n'est pas calculée correctement, toutes les lignes ont le même numéro


Même résultat, merci



0
votes

Bien qu'il s'agisse d'un exemple, votre clause WHERE renvoie essentiellement TOUS les patients. Ce qui tue probablement vos performances, c'est que vous faites 3 requêtes corrélées dans vos listes de champs en interrogeant à chaque fois pour chaque personne. Une fois pour la facture et deux fois pour les paiements.

Au lieu de cela, j'ai restructuré la requête basée sur PreQuery LEFT-JOINs aux tables de factures et de paiements. Si vous regardez, le tableau de la facture est pré-résumé avec un GROUP BY chaque ID patient. De même, par tableau des paiements, GROUP BY chaque ID patient. Ainsi, dans le pire des cas, chaque sous-requête renverra au PLUS un enregistrement pour un patient donné donnant le total de toutes les factures et les remises respectives. Pour les paiements, une somme de tous les paiements ET la date la plus récente.

Donc, avec ceci commençant par la table patient, je peux joindre à gauche sur l'ID patient commun, vous pouvez voir les valeurs récapitulatives simplifiées à la sortie finale et sera applicable à tous les patients. Oui, vous pouvez toujours ajouter des critères WHERE pour restreindre davantage, mais les performances devraient être nettement meilleures.

SELECT 
        p.patientid, 
        p.firstname, 
        p.lastname, 
        p.mobilephone, 
        p.email,
        coalesce( PatInv.JustSumOfAmount - PatInv.DiscountedAmounts, 0 )
            - coalesce( PatPay.PaidAmounts, 0 ) Answer,
        case when PatPay.PatientID IS NULL
            then ' '
            else Date_format( PatPay.LastPaymentDate, '%d-%m-%Y') end lastpaymentdate
    FROM 
        patient p
            LEFT JOIN
            ( select 
                    i.patientID,
                    sum( i.ammount ) justSumOfAmount,
                    sum( i.ammount * ( discount / 100 )) as discountedAmounts
                from
                    invoice i
                where
                    i.invoicedNumber > 0
                group by
                    i.patientID
                order by
                    i.patientid ) PatInv
                on p.patientid = patInv.patientID
            LEFT JOIN
            ( SELECT
                    pay.patientID, 
                    Sum(pay.ammount) paidAmounts,
                    max( pay.paymentDate ) LastPaymentDate
                FROM
                    payment pay
                group by
                    pay.patientID 
                order by
                    pay.patientid ) PatPay
                on p.patientID = patPay.PatientID

J'ai publié cette requête sur SQL Fiddle De plus, en regardant vos tables, vos factures et vos tables de paiement DEVRAIT CHACUN avoir un index sur l'ID patient pour aider à optimiser la requête . Je ne sais pas s'il s'agissait d'un exemple de surveillance de poste de votre sql-fiddle vs production, mais cela aussi aurait un impact sur les performances.

L'option SQLFiddle que j'ai prend 5 ms par rapport à vos 2-3 ms, mais cela est uniquement pour les quelques enregistrements fournis. Je parierais que contre plus de 1000 patients et 1000 de transactions dans chaque facture et table de paiement, cette option de requête sera plus rapide que les requêtes corrélées.

Considérez votre requête comme ceci. J'ai 1000 patients. Interrogez le tableau des factures 1 000 fois, interrogez le tableau des paiements 2 000 fois (1 000 pour la somme des paiements, 1 000 fois pour la date la plus récente par patient).

Ma requête - Faites une pré-requête sur le tableau des factures une fois et résumer 1 enregistrement par patient. Demandez une fois le tableau de paiement et récapitulez 1 enregistrement par patient. Joignez les patients à ces deux sous-tableaux directement par ID.


0 commentaires

0
votes

Les performances médiocres de tout système RDBM sont dues à une mauvaise conception. Dans votre SQL Fiddle, vous enregistrez des nombres dans le champ varchar . Votre moteur de table actuel est MyISAM qui ne prend pas en charge les relations !? Pas de relations => pas d'index => pas de recherches rapides

Afin d'améliorer les performances, je vous suggère de changer la conception de votre table. Le tableau des factures peut avoir les modifications suivantes. Changez le moteur en InnoDB et

ALTER TABLE `invoice` ENGINE = Innodb;

ALTER TABLE `invoice` 
CHANGE COLUMN `patientid` `patientid` INT(12) UNSIGNED NOT NULL ,
CHANGE COLUMN `ammount` `ammount` DECIMAL(14,2) NOT NULL ,
CHANGE COLUMN `discount` `discount` DECIMAL(3,2) NULL DEFAULT '0' ,
ADD INDEX `fk_invoice_patient_idx` (`patientid` ASC);
ALTER TABLE `invoice` 
ADD CONSTRAINT `fk_invoice_patient`
  FOREIGN KEY (`patientid`)
  REFERENCES `test`.`patient` (`patientid`)
  ON DELETE RESTRICT
  ON UPDATE CASCADE;

qui a instantanément amélioré toutes les recherches entre le patient et le tableau de facturation. Apportez les mêmes modifications à votre tableau de paiement, puis comparez vos résultats.

Après les modifications ci-dessus, vous pouvez créer des vues pour les paiements et les factures ou des sous-requêtes comme les autres mentionnées pour accélérer davantage.

p>


0 commentaires