使用EF进行缓慢的mysql查询

时间:2014-04-07 12:41:52

标签: c# mysql sql performance entity-framework

我需要每天/每周/每月进行一次相当大的搜索,并且对于速度有问题。我一直在增加缓冲区大小以使用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分钟?我有两次导入数据库的程序。我该怎么做才能让它更快?

1 个答案:

答案 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值,这可能是一个巨大的胜利。但这需要更改您的申请。