我需要每天/每周/每月进行一次相当大的搜索,并且对于速度有问题。我一直在增加缓冲区大小以使用50%的ram(2gb)和其他一些调整,但没有一个能够提高性能。
SELECT SUM(MessageCount) AS ErrorCount, Country, StatusCode, StatusText
FROM messages
WHERE StatusCode IN(3,4,5,6,8,9,10,11,13) AND SentOn >= 1394275285391 AND SentON < 1396863685391
GROUP BY Country, StatusCode
在mysql workshop中运行查询时需要大约50-70秒进行处理,该表包含大约6,500,000行。为了加快速度,我为StatusCode,SentOn和Country(= CHAR(2))添加了一个索引,并将其命名为ErrorCountries,如下所示。我对车间的速度并不高兴,但我想如果必须的话,我可以忍受它。
我做了一个解释并得到了这个结果:
id=1
select_typ=SIMPLE
table=messages type=range
possible_keys=SentOn,ErrorCountries
key=ErrorCountries
key_len=12
rows=290977
filter=100.00
extra=Using index condition; Using MRR; Using temporary; Using filesort
我猜临时和文件输出可能是速度问题。
因此,虽然我在研讨会上说查询需要50-70秒,但在我的程序中它的表现并不像这样。我在连接字符串中没有任何命令超时,所以我认为添加它会解决这个问题。但是,当我现在将超时更改为5分钟时,我开始变得更加困惑,问题确实存在......
var sql = "SELECT SUM(MessageCount) AS ErrorCount, Country, StatusCode, StatusText" +
" FROM messages" +
" WHERE StatusCode IN(3,4,5,6,8,9,10,11,13) AND SentOn >= " + @from + " AND SentOn < " + to +
" GROUP BY Country, StatusCode";
var res = db.Database.SqlQuery<Result>(sql).ToList();
为什么这个查询需要一分钟才能在研讨会上运行?为什么在程序中运行需要5分钟?我有两次导入数据库的程序。我该怎么做才能让它更快?
答案 0 :(得分:3)
您可以尝试做三件事来提高速度。
首先,您提到您在(StatusCode, SentOn, Country)
上创建了一个索引。您已走上正确的轨道,但此索引中的列顺序错误。
此查询对SentOn执行范围扫描,然后对StatusCode执行值选择,然后获取MessageCount,Country和StatusText详细信息字段。列索引中的第一列应该是您进行范围扫描的列。尝试在(SentOn, StatusCode, MessageCount, Country, StatusText)
上创建索引。这应该有助于加快您的查询。如果你想知道原因,请阅读有关索引的内容。
第二,似乎StatusCode和StatusText的值之间存在一对一的关系。我猜这是因为你没有按StatusText进行分组。
如果确实如此,请尝试仅使用此小子查询在StatusCode上执行摘要查询。
SELECT SUM(MessageCount) AS ErrorCount,
Country,
StatusCode
FROM messages
WHERE StatusCode IN (3,4,5,6,8,9,10,11,13)
AND SentOn >= 1394275285391
AND SentON < 1396863685391
GROUP BY Country, StatusCode
这会更快一些,因为你不必为了满足你的GROUP BY所需的数据混乱(filesort)内容来处理StatusText值。
您需要另一个子查询来将StatusCode与StatusText相关联。这可能会表现得非常糟糕;我建议你在继续之前尝试一下。
SELECT DISTINCT StatusCode, StatusText
FROM messages
WHERE StatusCode IN (3,4,5,6,8,9,10,11,13)
您可以通过在(StatusCode,StatusText)上创建复合索引来提高此子查询的性能。
然后尝试将这两个子查询连接在一起。
SELECT a.ErrorCount, a.Country, a.StatusCode, b.StatusText
FROM (
SELECT SUM(MessageCount) AS ErrorCount,
Country,
StatusCode
FROM messages
WHERE StatusCode IN (3,4,5,6,8,9,10,11,13)
AND SentOn >= 1394275285391
AND SentOn < 1396863685391
GROUP BY Country, StatusCode
) AS a
JOIN (
SELECT DISTINCT StatusCode, StatusText
FROM messages
WHERE StatusCode IN (3,4,5,6,8,9,10,11,13)
) AS b ON a.StatusCode=b.StatusCode
第三次,如果你可以完全从你的消息表中删除StatusText列并使自己成为一个小查找表来查找基于StatusCode的StatusText值,这可能是一个巨大的胜利。但这需要更改您的申请。