1

应用了所有过滤器的我的 SQL 查询返回 100 万(一百万)条记录。要获得所有记录需要 76.28 秒 .. 这是不可接受的。如何优化我的 SQL 查询,这应该花费更少的时间。我正在使用的查询是:

    SELECT cDistName , cTlkName, cGpName, cVlgName , 
           cMmbName , dSrvyOn 
      FROM sspk.villages 
 LEFT JOIN gps  ON nVlgGpID = nGpID
 LEFT JOIN TALUKS ON nGpTlkID = nTlkID   
 left JOIN dists ON nTlkDistID = nDistID
 LEFT JOIN HHINFO ON nHLstGpID = nGpID
 LEFT JOIN MEMBERS ON nHLstID = nMmbHhiID
 LEFT JOIN BNFTSTTS  ON nMmbID = nBStsMmbID
 LEFT JOIN STATUS ON nBStsSttsID = nSttsID
 LEFT JOIN  SCHEMES ON  nBStsSchID = nSchID
     WHERE (
               (nMmbGndrID = 1 and nMmbAge between 18 and 60) 
           or  (nMmbGndrID = 2 and nMmbAge between 18 and 55)
           )
      AND cSttsDesc like 'No, Eligible' 
      AND DATE_FORMAT(dSrvyOn , '%m-%Y') < DATE_FORMAT('2012-08-01' , '%m-%Y' )
 GROUP BY cDistName , cTlkName, cGpName, cVlgName , 
        DATE_FORMAT(dSrvyOn , '%m-%Y')

我在论坛和外部搜索并使用了一些给出的提示,但几乎没有任何区别。我在上面的查询中使用的连接是左连接全部在 Primary Key 和 Foreign key 上。任何人都可以建议我如何修改此 sql 以减少执行时间....

4

7 回答 7

2

先生,您是一个对 MySQL 要求很高的用户!以您提到的速度从大规模连接的结果集中检索一百万条记录是每条记录 76 微秒。许多人会认为这是可以接受的性能。请记住,您的客户端软件可能是具有该大小结果集的限制因素:它必须消耗巨大的结果集并对其进行处理。

话虽如此,我看到了几个问题。

首先,重写您的查询,使每个列名都由表名限定。您将为自己和下一个维护它的人执行此操作。您可以一目了然地看到您的WHERE标准需要做什么。

其次,考虑这个搜索标准。它需要两次搜索,因为OR.

 WHERE (
           (MEMBERS.nMmbGndrID = 1 and MEMBERS.nMmbAge between 18 and 60) 
       or  (MEMBERS.nMmbGndrID = 2 and MEMBERS.nMmbAge between 18 and 55)
       )

我猜这些标准符合您的大多数人口——18-60 岁的女性和 18-55 岁的男性(猜测)。您可以将 MEMBERS 表放在 LEFT JOIN 列表的首位吗?或者你可以在你的表中放置一个派生列(MEMBERS.working_age = 1 或类似的)吗?

还可以在 MEMBERS 上尝试 (nMmbGndrID,nMmbAge) 上的复合索引以加快速度。它可能会也可能不会起作用。

第三,考虑这个标准。

  AND DATE_FORMAT(dSrvyOn , '%m-%Y') < DATE_FORMAT('2012-08-01' , '%m-%Y' )

您已将函数应用于 dSrvyOn 列。这使该搜索无法使用索引。相反,试试这个。

  AND dSrvyOn >= '2102-08-01'
  AND dSrvyOn <  '2012-08-01' + INTERVAL 1 MONTH

如果您在 dSrvyOn 上有索引,这将在该索引上进行范围搜索。我的评论也适用于您的 ORDER BY 子句中的函数。

最后,正如其他人提到的,不要使用LIKE搜索 where =will do。column LIKE '%something%'如果您想要可接受的性能,切勿使用。

于 2012-11-21T13:48:32.600 回答
1

您声称自己是基于良好且唯一的索引的连接。所以几乎没有什么可以优化的。也许有一些提示:

  • 尝试优化您的表格布局,也许您可​​以减少所需的连接数。这可能带来比其他任何东西更多的性能优化。

  • 检查您的硬件(可用内存和其他东西)和服务器配置。

  • 使用 mysqlsexplain功能查找瓶颈。

  • 也许您可以专门为此查询创建一个辅助表,该表由后台进程填充。这样查询本身运行得更快,因为工作是在后台查询之前完成的。如果查询检索的数据不一定与数据库中的每一次更改同步,这通常会起作用。

  • 检查 RDBMS 是否真的是正确的数据库类型。出于许多目的,图数据库效率更高并提供更好的性能。

于 2012-11-21T13:34:11.793 回答
0

您的like操作员可能会阻止您——全文搜索like并不是 MySQL 的强项。

考虑设置全文索引cSttsDesc(首先确保它是一个TEXT字段)。

ALTER TABLE articles ADD FULLTEXT(cSttsDesc);

SELECT
    *
FROM
    table_name
 WHERE MATCH(cSttsDesc) AGAINST('No, Eligible')

或者,您可以设置一个布尔标志而不是cSttsDesc like 'No, Eligible'.

来源:http ://devzone.zend.com/26/using-mysql-full-text-searching/

于 2012-11-21T13:40:20.847 回答
0

您可以创建视图以避免长时间的查询和时间。

于 2012-11-21T13:31:55.640 回答
0

这个 SQL 有很多多余的东西,可能不会出现在explain.

如果您需要一个字段,则它不应该位于左联接中的表中 - 左联接适用于数据可能位于联接表中的情况,而不是必须存在的情况。

如果所有必填字段都在同一个表中,则它应该在您的第一个 FROM 中。

如果您的文本搜索是可预测的(不是来自用户输入)并且与单个已知 ID 相关,请使用 ID 而不是文本搜索(Patricia 用于发现 LIKE 瓶颈的道具)。

由于缺少表提示,您的查询很难阅读,但您的字段名称似乎确实存在模式。

您需要nMmbGndrIDnMmbAge有一个值,但这些可能在 MEMBERS 中,即 5 个左连接。那是冗余。

请记住,您可以像这样进行简单的连接:

FROM sspk.villages, gps, TALUKS, dists, HHINFO, MEMBERS [...] WHERE [...] nVlgGpID = nGpID AND nGpTlkID = nTlkID AND nTlkDistID = nDistID AND nHLstGpID = nGpID AND nHLstID = nMmbHhiID

看起来cSttsDesc来自STATUS. 但是,如果文本与其中的'No, Eligible'一个 nBStsSttsID 完全匹配,BNFTSTTS则找出该值并使用它!如果是 7,取出LEFT JOIN STATUS ON nBStsSttsID = nSttsID并替换AND cSttsDesc like 'No, Eligible'AND nBStsSttsID = '7'。这将大大提高速度。

于 2012-11-21T13:31:10.813 回答
0

如果连接中使用的表最少用于更新查询,那么您可以将引擎类型从 INNODB 更改为 MyISAM。

MyISAM 中的 Select 查询运行速度比 INNODB 快 2 倍,但 MyISAM 中的更新和插入查询要慢得多。

于 2012-11-21T13:31:25.547 回答
0

尝试向 nMmbGndrID、nMmbAge 和 cSttsDesc 添加索引,看看这是否有助于您的查询。

此外,您可以在您的 select 语句之前使用“解释”命令,为您提供一些关于您可以做得更好的提示。有关说明的更多详细信息,请参阅MySQL 参考

于 2012-11-21T13:26:29.417 回答