查询性能的一个大问题是内联视图(别名为 cust)。MySQL 将其称为“派生表”,这是一个恰当的名称,因为 MySQL 处理它的方式。MySQL 运行该查询,并将结果存储为临时 MyISAM 表,外部查询在该表上运行。因为该视图查询中没有谓词,所以 MySQL 本质上是
每次运行查询时创建客户表的副本。
从性能的角度来看,将搜索谓词从外部查询移动到内联视图中的查询会更好:
SELECT cust.*
, br.branchcode
, br.branchname
, over.branchcode override_branchcode
, over.branchname override_branchname
FROM ( SELECT s.id
, CONCAT(s.firstName,' ',s.lastName) fullName
, s.firstname
, s.lastname
, s.phone1
, s.phone2
, s.mobile1
, s.mobile2
, s.unit
, s.brgy
, s.city
, s.primary
, s.override_pst
FROM sl_customers s
WHERE CONCAT(s.firstName,' ',s.lastName) LIKE '{$searchtext}'
OR s.firstname LIKE '%{$searchtext}%'
OR s.lastname LIKE '%{$searchtext}%'
) cust
LEFT
JOIN sl_branches br
ON cust.primary = br.id
LEFT
JOIN sl_branches over
ON cust.override_pst = over.id
至少这可能是要复制到“派生表”中的行数较少,尽管 MySQL 仍然必须实现该视图查询,然后对其运行另一个查询。
为了更好地提高性能,我们可以完全消除内联视图:
SELECT s.id
, CONCAT(s.firstName,' ',s.lastName) fullName
, s.firstname
, s.lastname
, s.phone1
, s.phone2
, s.mobile1
, s.mobile2
, s.unit
, s.brgy
, s.city
, s.primary
, s.override_pst
, br.branchcode
, br.branchname
, over.branchcode override_branchcode
, over.branchname override_branchname
FROM sl_customers s
LEFT
JOIN sl_branches br
ON cust.primary = br.id
LEFT
JOIN sl_branches over
ON cust.override_pst = over.id
WHERE CONCAT(s.firstName,' ',s.lastName) LIKE '{$searchtext}'
OR s.firstname LIKE '%{$searchtext}%'
OR s.lastname LIKE '%{$searchtext}%'
就性能而言,下一个“大石头”是没有一个谓词是可搜索的。也就是说,MySQL 不能对这些 LIKE 谓词中的任何一个使用范围扫描(因为在列的情况下,前导 '%'),并且因为必须为每一行评估 CONCAT 表达式。
全表扫描可能是您使用此查询获得的最快速度。您也许可以让 MySQL 使用 index ON cust (firstname,lastname)
,但是如果表和索引在内存中,并且/或者只需要访问表中的一小部分行(由于通过索引查找访问基础表中的块的方式,随机读取速度较慢。)
当 searchtext 为空字符串时,完全扫描可能是最快的。
如果 searchtext 不匹配任何行,那么完整的索引扫描可能会更快。
你真的必须测试性能。
(很可能您已经在其他两个表的 id 列上有索引,因为该id
列可能是这些表的 PRIMARY KEY。如果不是这种情况,那么您肯定希望在这些表上定义一个带有 id 的索引作为前导列,以提高连接性能。)