2016-11-07 128 views
0

我几个月前写了这个查询。它运行良好。但是,这个查询一天比一天要慢。为什么这个查询需要这么长时间来执行

此查询检查除了同一个表执行以外的多个表中的帐单历史记录。

下面是该查询 -

SELECT * FROM (
      SELECT *,     
      (SELECT username FROM users WHERE id = u_bills.UserId) AS username, 
      (SELECT first_name FROM users WHERE id = u_bills.UserId) AS first_name, 
      (SELECT last_name FROM users WHERE id = u_bills.UserId) AS last_name, 
      (SELECT phone FROM users WHERE id = u_bills.UserId) AS phone, 
      (SELECT email FROM users WHERE id = u_bills.UserId) AS email, 
      (SELECT CPRate FROM cpt WHERE UserId = u_bills.UserId ORDER BY AddedDate DESC LIMIT 0,1) AS cprate, 
      (SELECT (SELECT PopName FROM pops WHERE PopId = p.PopName) AS PopFullName FROM u_setupinfos AS p 
      WHERE UserId = u_bills.UserId) AS popname, 
      (SELECT active FROM users WHERE id = u_bills.UserId) AS active,     
      (SELECT SUM(PaidAmount) AS PaidAmount FROM u_billhistory 
      WHERE UserId = u_bills.UserId AND MONTH(AddedDate) = MONTH(PaidDate)) AS PaidAmount, 
      (SELECT PaidDate FROM u_billhistory 
      WHERE UserId = u_bills.UserId AND MONTH(AddedDate) = MONTH(PaidDate) 
      GROUP BY MONTH(PaidDate)) AS PaidDate, 
      (SELECT PaymentMedia FROM u_billhistory 
      WHERE UserId = u_bills.UserId AND MONTH(AddedDate) = MONTH(PaidDate) 
      GROUP BY MONTH(PaidDate)) AS PaymentMedia, 
    (SELECT TransactionId FROM u_billhistory 
      WHERE UserId = u_bills.UserId AND MONTH(AddedDate) = MONTH(PaidDate) GROUP BY MONTH(PaidDate)) AS TransactionId, 
      (SELECT GROUP_CONCAT(CONCAT(`BillHisId`,';',`PaidAmount`,';',`PaidDate`) separator '|') AS vals 
FROM u_billhistory 
WHERE UserId = u_bills.UserId 
AND YEAR(PaidDate) = YEAR(CURDATE())) AS TotalPaids 
      FROM u_bills) AS m 
     WHERE m.username = 'abc' 

请查阅图像 -

enter image description here

我想组织此查询的EXPLAIN报告。我需要建议使这个查询更快,例如3到5秒,而不是1分半钟或更长。我在这个查询中犯了什么错误?

重要笔记记录

我使用的查询索引几乎每一列

+0

也许没有 - 您是否更新过服务器上的统计信息?那段时间你的数据如何增长?还有其他数据库争夺资源吗? –

+4

这就是说 - 为什么所有的子查询一次只能得到一个字段? –

+2

,因为它的巨大与subquerys –

回答

5

,因为你让运行一个单独的查询到一个额外的表在结果每条记录的每个字段它很慢...有时不止一个。您应该使用JOIN而不是嵌套的SELECT。对于某些分组结果,可以加入SELECT声明,该声明具有自己的GROUP BY。


此外,在各列单独的索引不帮!

想象索引像电话簿。一个简单的电话簿在Last Name和First Name上使用聚簇索引。然后它还列出了每个项目的地址和电话号码。这就是聚集索引的含义:只是存储数据的顺序。

其他索引就像补充。 “电话号码”上的非聚集索引就像书本末尾的一个补充,按顺序列出电话号码,然后显示姓氏和名字(但不是地址)。 “地址”的索引也会这样做:一个单独的补充程序,按顺序列出地址,然后给出名称。

有了这些索引的补充,如果你有一个电话号码并且想知道地址,你必须首先在补充中查找电话号码以找到名字,然后在主要书籍中查找名字以获得地址。在这个例子中,手机补充帮助,因为它比电话簿的全面扫描更好。

但是,这里要注意的重要一点是地址补充_does 而不是有助于此搜索,即使地址是您想要查找的确切字段。它可能可用于其他搜索,但它在这种情况下不起作用。此外,请记住,每次更新您的图书需要您不仅更新图书,还更新所有补充图书。这不仅仅是存储空间,而是更新每个索引的时间。你需要考虑是否值得。如果你有一堆未被使用的索引,没有它们你最好。


再回到您的特定问题,关于的唯一指标,这将真正帮助你u_bills.usernameuser.UserId(希望的为它的表簇)和两个u_billhistory.UserIdu_billhistory.PaidDate单一指标。

这里是在重构这个查询的初步尝试:

SELECT ub.*, u.username, u.first_name, u.last_name, u.phone, u.email, u.active, 
    m.PaidAmount, m.PaymentMedia, m.TransactionId, 
    y.TotalPaids, p.PopName As PopFullName, cpt2.CPRate  

FROM u_bills ub 
INNER JOIN users u on u.id = ub.UserId 
INNER JOIN u_setupinfos usi on usi.UserId = ub.UserID 
INNER JOIN pops p ON p.PopId = usi.PopName 
INNER JOIN (
    SELECT UserId, MIN(AddedDate) As cptDate 
    FROM cpt 
    GROUP BY UserID   
) cpt1 ON cp1.UserID = ub.UserID 
INNER JOIN (
    SELECT UserID, AddedDate, MIN(CPRate) AS CPRate 
    FROM cpt 
    GROUP BY UserID, AddedDate 
) cpt2 ON cpt2.UserID = ub.UserID AND cpt2.AddedDate = cpt1.ctpDate 
INNER JOIN (
    SELECT UserID, MONTH(PaidDate) PaidMonth, SUM(PaidAmount) AS PaidAmount, 
     PaymentMedia, TransactionId --these two fields need an aggregate function of some type! 
    FROM u_billhistory 
    GROUP BY UserId, MONTH(PaidDate) 
) m ON m.UserID = ub.UserId AND m.PaidMonth = MONTH(ub.AddedDate) 
INNER JOIN (
    SELECT UserID, YEAR(PaidDate) As PaidYear, 
     GROUP_CONCAT(CONCAT(`BillHisId`,';',`PaidAmount`,';',`PaidDate`) separator '|') AS TotalPaids 
    FROM u_billhistory 
    WHERE YEAR(PaidDate) = YEAR(CurDate()) 
    GROUP BY UserId, YEAR(PaidDate) 
) y ON Y.UserId = ub.UserId 
WHERE username='abc' 

请注意,这不是很完整,因为我们不知道所有的关于您的架构和数据的信息,什么似乎因为有缺失GROUP BY和两个缺失的聚合函数。 MySql这种方式很糟糕......一个更好的数据库不会让你的查询运行,直到你修复这些东西。

+0

m.username有一个where子句所以那里的索引会有所帮助。 – nicomp

+1

正在处理它..格式化使评估一些其他表需要更多的时间。 –

+0

@JoelCoehoorn感谢您的努力。不幸的是,它返回空。我知道编写一个没有模式的查询很困难。如果你问,那么我可以给你我的查询输出。希望这会有所帮助。我已经尝试了几个其他选择你的查询。 –

相关问题