Database 如何处理耗时的SQL?
我们有一个包含600万条记录的表,然后我们有一个SQL,它需要大约7分钟来查询结果。我认为SQL不能再优化了 查询时间导致我们的weblogic抛出max stuck thread异常 对我处理这个问题有什么建议吗 以下是问题,但我很难改变它Database 如何处理耗时的SQL?,database,oracle,query-optimization,Database,Oracle,Query Optimization,我们有一个包含600万条记录的表,然后我们有一个SQL,它需要大约7分钟来查询结果。我认为SQL不能再优化了 查询时间导致我们的weblogic抛出max stuck thread异常 对我处理这个问题有什么建议吗 以下是问题,但我很难改变它 SELECT * FROM table1 WHERE trim(StudentID) IN ('354354','0') AND concat(concat(substr(table1.LogDate,7,10),'/'),substr(table1
SELECT * FROM table1
WHERE trim(StudentID) IN ('354354','0')
AND concat(concat(substr(table1.LogDate,7,10),'/'),substr(table1.LogDate,1,5))
BETWEEN '2009/02/02' AND '2009/03/02'
AND TerminalType='1'
AND RecStatus='0' ORDER BY StudentID, LogDate DESC, LogTime
然而,我知道使用字符串来比较日期很费时,但有人在我无法更改表结构之前写过
LogDate被定义为一个字符串,格式为mm/dd/yyyy,因此我们需要对其进行子字符串和concate处理,以便在。。。而且。。。我认为很难在这里进行优化。如果没有关于正在执行的查询类型以及是否使用索引的进一步信息,就很难给出任何具体信息 但这里有一些一般的提示
count()
trim()
,尝试从查询中删除trim()
。这样,您只需使用索引查找StudentID
此外,date
过滤器应该可以在数据库中本地使用。在不知道哪个数据库的情况下,这可能会更困难,但类似的方法可能会起作用:LogDate介于'2009-02-02'和'2009-02-02'之间。
如果同时在所有这些列上添加索引(即StudentID
、LogDate
、TerminalType
、RecStatus
和EmployeeID
),则其速度应该会非常快
但是查询时间导致我们的weblogic抛出max stuck thread异常
如果查询需要7分钟且无法加快速度,则必须停止实时运行此查询。能否将应用程序更改为查询定期刷新的缓存结果表
在此之前,您可以实现一个闩锁(在Java中),一次只允许一个线程执行此查询。第二个线程将立即失败并出现错误(而不是导致整个系统崩溃)。这可能不会让此查询的用户感到高兴,但至少它可以保护所有其他线程
我更新了查询,你能给我一些建议吗
这些字符串操作使得索引几乎不可能。你确定你至少不能摆脱“修剪”吗?实际数据中真的有多余的空白吗?如果是这样,你可以缩小范围,只使用一个学生id,这应该会大大加快速度
您希望在(学生id、日志日期)上创建一个复合索引,并且希望仍然可以使用索引范围扫描(针对给定的学生id)来解决复杂的日志日期问题。如果您的数据库支持,您可能希望尝试一种新的方法
如果不是这样的话,可能值得考虑自己实现类似的功能,通过安排一个作业来运行一个查询,该查询将执行昂贵的修剪和合并,并用结果刷新一个表,这样您就可以针对更好的表运行一个查询并避免昂贵的内容。或者使用触发器来维护这样一个表。你提供的信息很少,我的直觉是以下条款给了我们一个线索:
... WHERE trim(StudentID) IN ('354354','0')
如果您有大量未识别学生的记录(即studentID=0),则studentID索引将非常不平衡
在600万条记录中,有多少条记录的studentId=0?在不知道您使用的是什么数据库以及您的表结构的情况下,很难提出任何改进建议,但可以通过使用索引、提示等来改进查询 在您的查询中,将显示以下部分
在“2009/02/02”和“2009/02/02”之间的年份(年份(表1.LogDate,7,10),“/”),年份(表1.LogDate,1,5))
太有趣了。在2009/02/02和2009/02/02之间?伙计,你想做什么
你能把你的桌子结构贴在这里吗
600万张唱片也不是什么大事
SELECT * ... WHERE trim(StudentID) IN ('354354','0')
如果这是正常构造,那么您需要一个。因为如果没有它,您将强制DB服务器执行完全表扫描
根据经验,您应该尽可能避免使用
WHERE
子句中的函数。trim(stundertId)
,substr(表1.LogDate,7,10)
禁止DB服务器使用任何索引或对查询应用任何优化。尽可能多地使用本机数据类型,例如DATE
而不是VARCHAR
,因为LogDate
StudentID
也应在客户端软件中进行适当管理,例如在INSE之前修剪数据RT
/更新
此查询很可能正在执行完整的文件扫描,因为您所在的环境不太可能利用任何索引
是日期字段还是文本字段?如果它是日期字段,那么不要做子字符串和CONTAT。只要说“092-02-02”和“09-02-03”之间的“日志日期”或日期范围是什么。如果将其定义为文本字段,则应认真考虑将其重新定义为日期字段。(如果您的日期确实是文本,并且是在mm/dd/yyyy上写的,那么如果日期跨越一年以上,那么您的订单…LOGDATE DESC将不会给出有用的结果。)
有必要对StudentID进行修剪吗?最好在将数据放入数据库之前清理数据,然后在每次检索数据时尝试清理数据 如果LogDate被定义为一个日期,并且您可以在输入时修剪studentid,那么SELECT * FROM table1
WHERE StudentID IN (:SearchStudentId,0)
AND table1.LogDate = :SearchDate
AND TerminalType='1'
AND RecStatus='0'
ORDER BY EmployeeID, LogDate DESC, LogTime
SELECT * FROM table1
WHERE StudentID IN (:SearchStudentId,:StudentId0)
AND table1.LogDate BETWEEN :SearchDate AND :SearchDate+0.99999
AND TerminalType='1'
AND RecStatus='0'
ORDER BY EmployeeID, LogDate DESC, LogTime
StudentID IN (lpad('354354',10),lpad('0',10))