select tblfarmerdetails.ncode,
tblfarmerdetails.region,tblfarmerdetails.province, tblfarmerdetails.municipality,
concat(tblfarmerdetails.farmerfname, ' ', tblfarmerdetails.farmerlname) as nameoffarmer,
concat(tblfarmerdetails.spousefname, ' ',tblfarmerdetails.spouselname) as nameofspouse, tblstatus.statusoffarmer from tblfarmerdetails
INNER Join
tblstatus on tblstatus.ncode = tblfarmerdetails.ncode where tblstatus.ncode = tblfarmerdetails.ncode order by tblfarmerdetails.region
检索11.2m数据需要很长时间。我将如何改进此查询?
答案 0 :(得分:2)
首先,对查询进行格式化,使其可读或至少可被人识别。
SELECT f.ncode
, f.region
, f.province
, f.municipality
, CONCAT(f.farmerfname,' ',f.farmerlname) AS nameoffarmer
, CONCAT(f.spousefname,' ',f.spouselname) AS nameofspouse
, s.statusoffarmer
FROM tblfarmerdetails
JOIN tblstatus s
ON s.ncode = f.ncode
ORDER BY f.region
可能需要花费大量时间来执行“使用filesort”操作,以按ORDER BY
子句中指定的顺序对所有行进行排序。如果没有前导列为region
的索引,肯定会发生排序操作。
有适当的索引,例如
... ON tblfarmerdetails (region, ... )
意味着MySQL可以使用索引“按顺序”返回行,而无需进行排序操作。
如果MySQL有一个“覆盖索引”可用,即一个索引包含查询中表引用列的所有,MySQL可以利用该索引来满足查询而不需要访问基础表格中的页面。
但考虑到列的数量,以及其中一些列的大小可能是VARCHAR的可能性,这可能是不可能的或不可行的:
... ON tblfarmerdetails (region, ncode, province, municipality, farmerfname, farmerlname, spousefname, spouselname)
(MySQL确实对indexex有一些限制。“覆盖索引”的目标是避免查找表中的页面。)
确保MySQL知道ncode
中的tblstatus
是唯一的。{1}}。无论是PRIMARY KEY还是UNIQUE索引。
我们怀疑tblstatus
表包含少量行,因此连接操作可能并不昂贵。但是,以ncode为主要列的适当覆盖索引不会受到影响:
... ON tblstatus (ncode, statusoffarmer)
如果MySQL必须执行“使用filesort”操作来获取所排序的行(以满足ORDER BY
子句),在大型集合上,该操作可以溢出到磁盘,并且可以添加(有时显着) )到经过的时间。
查询生成的结果集必须传输到客户端。这也可能需要一些时钟。
客户端必须对返回的行执行某些操作。
你确定你真的需要返回11.2M行吗?或者,你只需要前几千行吗?
考虑在查询中添加LIMIT
子句。
这些lname
和fname
列有多长?您是否需要MySQL为您进行连接,或者可以在行进行时在客户端上完成。
MySQL可能必须执行“使用临时”来保存具有连接结果的行。并且MySQL可能为该返回列分配足够的空间,以保持lname +最大可能长度与fname的最大可能长度。如果这是一个多字节字符字符集,那么将在单个字节字符集上将存储空间增加一倍或三倍。
要真正了解正在发生的事情,您需要查看查询执行计划。通过在SELECT语句前面加上关键字EXPLAIN
来获得它EXPLAIN SELECT ...
该输出将显示MySQL将要执行的操作,它将使用哪些索引。有了MySQL优化器可以执行的操作的知识,我们可以用它来做出一些非常好的猜测,以获得最大的收益。