什么是针对患者表中的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秒
答案 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
可立即改善患者和发票表之间的任何查找。对付款表进行相同的更改,然后比较您的结果。
进行上述更改后,您可以像上面提到的其他视图一样创建付款和发票或子查询的视图,以加快处理速度。