
[英]Optimizing MySQL Left join query between 3 tables to reduce execution time
[英]Optimizing the SQL Query to reduce execution time
应用了所有过滤器的SQL查询返回了10万(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')
我在论坛和外面搜索并使用了一些提示,但它几乎没有任何区别。 我在上面的查询中使用的连接在主键和外键上保持连接。 任何人都可以建议我如何修改这个SQL以减少执行时间....
先生,你是一个非常苛刻的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
来搜索=
将要执行的操作。 如果您想要可接受的性能,切勿使用column LIKE '%something%'
。
您声称自己是基于良好和独特索引的联接。 所以没有什么可以优化的。 也许有一些提示:
尝试优化您的表格布局,也许您可以减少所需的连接数量。 这可能带来比其他任何东西更多的性能优化。
检查您的硬件(可用内存和东西)和服务器配置。
使用mysqls explain
功能查找瓶颈。
也许你可以创建一个辅助表,特别是这个查询,由后台进程填充。 这样查询本身运行得更快,因为工作是在后台查询之前完成的。 如果查询检索的数据必须不必与数据库中的每个单独更改同步,那么这通常有效。
检查RDBMS是否真的是正确的数据库类型。 出于许多目的,图形数据库效率更高,性能更好。
尝试向nMmbGndrID,nMmbAge和cSttsDesc添加索引,看看是否有助于您的查询。
此外,您可以在select语句之前使用“Explain”命令,为您提供有关可能做得更好的一些提示。 有关说明的更多详细信息,请参阅MySQL参考 。
这个SQL有很多冗余的东西,可能不会在explain
显示出来。
如果你需要一个字段,它不应该在LEFT JOIN中的表中 - 左连接是指数据可能在连接表中,而不是必须时。
如果所有必填字段都在同一个表中,那么它应该是您第一个FROM中的字段。
如果您的文本搜索是可预测的(不是来自用户输入)并且与单个已知ID相关,则使用ID而不是文本搜索(使用Patricia来查找LIKE瓶颈)。
由于缺少表格提示,您的查询很难阅读,但您的字段名称似乎确实存在模式。
你需要nMmbGndrID
和nMmbAge
来获得一个值,但是这些可能是在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'
在BNFTSTTS
中恰好匹配一个nBStsSttsID,那么找出该值并使用它! 如果是7,则在LEFT JOIN STATUS ON nBStsSttsID = nSttsID
取出LEFT JOIN STATUS ON nBStsSttsID = nSttsID
并用AND nBStsSttsID = '7'
替换AND cSttsDesc like 'No, Eligible'
AND nBStsSttsID = '7'
。 这将大大提高速度。
如果连接中使用的表最少用于更新查询,那么您可以将引擎类型从INNODB更改为MyISAM。
MyISAM中的选择查询运行速度比INNODB快2倍,但MyISAM中的更新和插入查询要慢得多。
您可以创建视图以避免长查询和时间。
你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/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.