【问题标题】:SQL statement hanging up in MySQL databaseSQL 语句挂在 MySQL 数据库中
【发布时间】:2014-06-11 19:22:46
【问题描述】:

我需要一些 SQL 帮助。我有一个 SELECT 语句,它引用了几个表并挂在 MySQL 数据库中。我想知道是否有更好的方法来编写这个语句,以便它有效地运行并且不会挂起数据库?任何帮助/方向将不胜感激。谢谢。

代码如下:

Select Max(b.BurID) As BurID 
From My.AppTable a, 
My.AddressTable c, 
My.BurTable b 
Where a.AppID = c.AppID 
And c.AppID = b.AppID 
And (a.Forename = 'Bugs' 
And a.Surname = 'Bunny' 
And a.DOB = '1936-01-16' 
And c.PostcodeAnywhereBuildingNumber = '999' 
And c.PostcodeAnywherePostcode = 'SK99 9Q9' 
And c.isPrimary = 1 
And b.ErrorInd <> 1  
And DateDiff(CurDate(), a.ApplicationDate) <= 30)

日志中没有mysql错误。对不起。

【问题讨论】:

  • 确保在连接中使用的所有列都有索引。此外,虽然它对性能没有影响,但请尝试编写显式连接而不是隐式连接。
  • 你可以让你的日期依赖条件sargable
  • 我很难相信这个查询会花很长时间。可能还有其他事情发生。也许桌子被锁定了?检查是否还有其他打开的连接。

标签: mysql sql database-performance


【解决方案1】:

专业提示:使用显式 JOIN 而不是逗号分隔的表列表。以这种方式更容易看到您用于 JOIN 的逻辑。重写你的查询来做到这一点给了我们这个。

select Max(b.BurID) As BurID 
  From My.AppTable AS a 
  JOIN My.AddressTable AS c ON a.AppID = c.AppID 
  JOIN My.BurTable  AS b ON c.AppID = b.AppID
 WHERE (a.Forename = 'Bugs' 
   And a.Surname = 'Bunny' 
   And a.DOB = '1936-01-16' 
   And c.PostcodeAnywhereBuildingNumber = '999' 
   And c.PostcodeAnywherePostcode = 'SK99 9Q9' 
   And c.isPrimary = 1 
   And b.ErrorInd <> 1  
   And DateDiff(CurDate(), a.ApplicationDate) <= 30)

下一个专业提示:不要在WHERE 子句中使用函数(如DateDiff()),因为它们会破坏使用索引进行搜索。这意味着您应该将查询的最后一行更改为

  AND a.ApplicationDate >= CurDate() - INTERVAL 30 DAY

这与您的查询具有相同的逻辑,但它在搜索表达式中留下了一个裸露的(因此是可索引搜索的)列名。

接下来,我们需要查看您的列以了解您的搜索方式,并创建适当的索引。

让我们从AppTable 开始。您正在按 ForenameSurnameDOB 的特定值进行筛选。您正在通过一系列 ApplicationDate 值进行筛选。最后,您需要AppID 来管理您的加入。所以,这个复合索引应该会有所帮助。它的列按正确的顺序使用 range scan 来满足您的查询,并包含所需的结果。

 CREATE INDEX search1 USING BTREE 
     ON AppTable 
        (Forename, Surname, DOB, ApplicationDate, AppID)

接下来,我们可以查看您的AddressTable。类似的逻辑适用。您将通过 JOINed AppID 进入此表,然后按三列的特定值进行筛选。所以,试试这个索引

 CREATE INDEX search2 USING BTREE 
     ON AddressTable 
        (AppID, PostcodeAnywherePostcode, PostcodeAnywhereBuildingNumber, isPrimary)

最后,我们联系您的BurTable。使用和其他两个类似的逻辑,试试这个索引。

 CREATE INDEX search3 USING BTREE 
     ON BurTable 
        (AppID, ErrorInd, BurID)

这种索引称为compound covering index,可以大大加快您所询问的那种摘要查询。

【讨论】:

  • 谢谢奥利。我很欣赏全面的答复。很棒的信息。虽然当我提出你对 DATEDIFF 函数的建议时,我没有得到预期的结果。
  • 您的预期结果是什么?我的逻辑是否正确?我经常误读DATEDIFF() 函数。超过三十天前的申请日期?
  • 非常感谢您指出隐式连接的 SQL 反模式的使用。
  • 嘿 Ollie,当我使用 DATEDIFF() 执行语句时,我得到 14 条记录。当我插入您的建议时,我得到 0 条记录。这些是我的预期结果。过去 30 天内的申请日期。再次感谢。
  • 该死。我读错了 Datediff。我经常这样做。我将编辑我的答案以将&lt;= 翻转为&gt;=。只是出于好奇,您看到了多少性能提升?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-17
  • 1970-01-01
  • 2021-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多