针对患者表中的1000位患者优化此查询

时间:2019-02-19 12:55:19

标签: mysql mysqli

什么是针对患者表中的1000位患者优化此查询的最佳方法:

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 


[Patient Table][1]
[Invoice Table][2]
[Payment Table][3]
[Result Data][4]


  [1]: https://i.stack.imgur.com/rtCnm.png
  [2]: https://i.stack.imgur.com/czWKk.png
  [3]: https://i.stack.imgur.com/DRJnQ.png
  [4]: https://i.stack.imgur.com/XakbX.png

在Amazon EC2 t2.micro上花费10秒

This is the sql fiddle example

3 个答案:

答案 0 :(得分:1)

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 

这将更快地工作!!!!

尝试一下,让我知道

更新
我已将WHERE子句替换为内部联接,这将有助于快速获取数据。
我还要补充一点,如果主键上没有索引,请添加。

答案 1 :(得分:0)

尽管有一个例子,但您的WHERE子句基本上是返回ALL患者。可能会损害您的性能的是,您通过每次查询每个人来在字段列表中执行3个相关查询。一次用于发票,两次用于付款。

相反,我将基于PreQuery LEFT-JOIN的查询重组为发票和付款表。如果您看一下,发票表将预先汇总每个患者ID的GROUP BY。同样,通过付款表GROUP BY每个患者ID。因此,在最坏的情况下,对于给定的患者,每个子查询都将以MOST返回一条记录,给出所有发票的总金额和相应的折扣。对于付款,是所有付款和最近日期的总和。

因此,从患者表格开始,我可以在通用患者ID上左键连接,您可以看到简化的摘要值到最终输出,并将适用于所有患者。是的,您仍然可以添加WHERE条件以进一步限制,但这应该会明显更好。

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

我已将此查询发布在SQL Fiddle上,此外,应查看您的表,您的发票和付款表应在患者ID上都有索引,以帮助优化查询。我不知道这是否是您的sql-fiddle与生产中的示例事后监督,但这也会对性能产生影响。

我使用的SQLFiddle选项花费5毫秒,而您的2-3毫秒,但这仅适用于提供的一些记录。我敢打赌,针对每个发票和付款表中的1000多名患者和1000笔交易,这将使此查询选项比相关查询更快。

这样考虑您的查询。我有1000个病人。查询发票表1000次,查询付款表2000次(付款总和为1000,每个患者的最近日期为另外1000次)。

我的查询-预查询发票表一次,并汇总每位患者1条记录。预先查询付款表一次,并汇总每位患者1条记录。通过ID直接将患者加入这两个子表。

答案 2 :(得分:0)

在任何RDBM系统中,不良的性能归因于不良的设计。在SQL Fiddle中,您将数字保存在private static readonly Random Random = new Random(); private static readonly List<string> Rewards = new List<string> {"potion", "bomb", "gold"}; private static void Main() { // Initialize an inventory dictionary based on the shared list of rewards var inventory = Rewards.ToDictionary(key => key, value => 0); // Grab the Key of a random item in the dictionary for the reward var reward = inventory.ElementAt(Random.Next(inventory.Count)).Key; // Increment the value at that Key inventory[reward]++; } 字段中。您当前的表引擎是MyISAM,它不支持关系! varchar

为了提高性能,建议您更改表设计。 发票表可能有以下更改。 No relationships => no index => no quick lookups

Change Engine to InnoDB

可立即改善患者和发票表之间的任何查找。对付款表进行相同的更改,然后比较您的结果。

进行上述更改后,您可以像上面提到的其他视图一样创建付款和发票或子查询的视图,以加快处理速度。