我不明白这两个select ac.AccountNumber
, p.LicPLateno
, p.LicPlateState
, p.LicPlateCountry
, ISNULL(vm.VehicleMakeDesc,'Other')
, p.VehicleModel
, p.VehicleYear
, v.VehShortDesc
, ISNULL(p.VehicleMakeId,'-1') VechicleMakeId --(-1 means Other)
--, p.VehicleMakeId
from account ac
inner join Plate p on ac.AccountId=p.AccountId
inner join VehClass v on p.VehClassId=v.VehClassID
left join VehicleMake vm on p.VehicleMakeId=vm.VehicleMakeId
where ac.AccountNumber= '12345678'
and p.PlateStatusId=1 --(For Active Plates only)
and p.EndDate is null --(Plates are not expired)
order by p.LicPlateNo
;
的区别(第2行)。也许有人暗示我为什么mysql在这些方面的行为如此不同,这严重影响了查询速度。
慢查询持续12秒(等于查询具有该查询的所有行)并在整数列上使用连接,而连接表只有3条记录:
EXPLAIN
快速查询只消耗几分之一秒,在varchar(32)列上使用连接,连接表有1352条记录:
SELECT `inv_assets`.`id` AS `id`, `site`.`description` AS `sitename`,
(SELECT COALESCE(DATE_FORMAT(CONVERT_TZ(MIN(inspdate),'UTC','Europe/Vienna'),'%Y-%m-%d'),'')
FROM `mobuto_inv_inspections` AS `nextinsp`
WHERE ((`nextinsp`.`objectlink` = `inv_assets`.`id`
AND `nextinsp`.`inspdate` >= NOW()))
) AS `nextinsp`
FROM `mobuto_inv_assets` AS `inv_assets`
LEFT JOIN `mobuto_inv_sites` AS `site`
ON (`site`.`siteid` = `inv_assets`.`site`
AND `site`.`_state` IN (2,0))
ORDER BY `inv_assets`.`type` ASC LIMIT 0, 20;
+----+--------------------+------------+--------+----------------+---------+---------+------------------------------+-------+----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+------------+--------+----------------+---------+---------+------------------------------+-------+----------------------------------------------------+
| 1 | PRIMARY | inv_assets | ALL | NULL | NULL | NULL | NULL | 24857 | Using temporary; Using filesort |
| 1 | PRIMARY | site | ALL | PRIMARY,_state | NULL | NULL | NULL | 3 | Using where; Using join buffer (Block Nested Loop) |
| 2 | DEPENDENT SUBQUERY | nextinsp | ALL | inspdate | NULL | NULL | NULL | 915 | Using where |
+----+--------------------+------------+--------+----------------+---------+---------+------------------------------+-------+----------------------------------------------------+
对我来说奇怪的是,当我删除'column-select-part'中连接表的列(SELECT `inv_assets`.`id` AS `id`, `guarantor`.`lastname` AS `guarantoruname`,
(SELECT COALESCE(DATE_FORMAT(CONVERT_TZ(MIN(inspdate),'UTC','Europe/Vienna'),'%Y-%m-%d'),'')
FROM `mobuto_inv_inspections` AS `nextinsp`
LEFT JOIN `users` AS `saveuser`
ON (`saveuser`.`uid` = `nextinsp`.`saveuser`
AND `saveuser`.`_state` = '0')
WHERE ((`nextinsp`.`objectlink` = `inv_assets`.`id`
AND `nextinsp`.`inspdate` >= NOW()))
) AS `nextinsp`
FROM `mobuto_inv_assets` AS `inv_assets`
LEFT JOIN `users` AS `guarantor`
ON (`guarantor`.`uid` = `inv_assets`.`guarantor`
AND `guarantor`.`_state` = '0')
ORDER BY `inv_assets`.`type` ASC LIMIT 0, 20;
+----+--------------------+------------+--------+----------------+---------+---------+---------------------------------+-------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+------------+--------+----------------+---------+---------+---------------------------------+-------+----------------+
| 1 | PRIMARY | inv_assets | ALL | NULL | NULL | NULL | NULL | 24857 | Using filesort |
| 1 | PRIMARY | guarantor | eq_ref | PRIMARY,_state | PRIMARY | 98 | mobuto_dev.inv_assets.guarantor | 1 | Using where |
| 2 | DEPENDENT SUBQUERY | nextinsp | ALL | inspdate | NULL | NULL | NULL | 915 | Using where |
| 2 | DEPENDENT SUBQUERY | saveuser | eq_ref | PRIMARY,_state | PRIMARY | 98 | mobuto_dev.nextinsp.saveuser | 1 | Using where |
+----+--------------------+------------+--------+----------------+---------+---------+---------------------------------+-------+----------------+
)时(连接仍然存在且IMHO mysql不会优化它时)没用过),速度又回来了(因为mysql不再使用临时表,解释看起来和快速表一样,有description
)。
但是为什么只有在没有选择列时才能为第一个样本工作,而我可以在第二个样本中选择一个!?
type=eq_ref
根据@Wilson Hauck的要求进行更改:
CREATE TABLE `mobuto_inv_assets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`invnum` varchar(10) NOT NULL,
`oebglcat` varchar(4) NOT NULL,
`mark` varchar(100) NOT NULL,
`type` varchar(100) NOT NULL,
`serialnum` varchar(100) NOT NULL,
`desc` varchar(100) NOT NULL,
`site` int(11) NOT NULL DEFAULT '0',
`licnum` varchar(20) NOT NULL DEFAULT '',
`inquirer` varchar(100) NOT NULL DEFAULT '',
`inqdate` date NOT NULL DEFAULT '0000-00-00',
`supplier` varchar(100) NOT NULL DEFAULT '',
`suppldate` date NOT NULL DEFAULT '0000-00-00',
`supplnumber` varchar(30) NOT NULL DEFAULT '',
`invoicedate` date NOT NULL DEFAULT '0000-00-00',
`invoicenumber` varchar(30) NOT NULL DEFAULT '',
`purchaseprice` decimal(11,2) NOT NULL DEFAULT '0.00',
`leased` varchar(1) NOT NULL DEFAULT 'N',
`leasingcompany` varchar(100) NOT NULL DEFAULT '',
`leasingnumber` varchar(30) NOT NULL DEFAULT '',
`notes` text NOT NULL,
`inspnotes` text NOT NULL,
`inactive` varchar(1) NOT NULL DEFAULT 'N',
`maintain` varchar(1) NOT NULL DEFAULT 'Y',
`asset` varchar(1) NOT NULL DEFAULT 'Y',
`inspection` varchar(1) NOT NULL DEFAULT '',
`inspperson` varchar(100) NOT NULL DEFAULT '',
`guarantor` varchar(32) NOT NULL DEFAULT '',
`saveuser` varchar(32) NOT NULL,
`savetime` int(11) NOT NULL,
`recordid` varchar(32) NOT NULL,
`_state` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `invnum` (`invnum`),
KEY `_state` (`_state`),
KEY `site` (`site`)
) ENGINE=InnoDB AUTO_INCREMENT=30707 DEFAULT CHARSET=utf8;
CREATE TABLE `mobuto_inv_sites` (
`siteid` int(11) NOT NULL AUTO_INCREMENT,
`description` varchar(100) NOT NULL,
`saveuser` varchar(32) NOT NULL,
`savetime` int(11) NOT NULL,
`recordid` varchar(32) NOT NULL,
`_state` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`siteid`),
KEY `_state` (`_state`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
mysql> SHOW INDEX FROM mobuto_inv_assets;
+-------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| mobuto_inv_assets | 0 | PRIMARY | 1 | id | A | 24857 | NULL | NULL | | BTREE | | |
| mobuto_inv_assets | 0 | invnum | 1 | invnum | A | 24857 | NULL | NULL | | BTREE | | |
| mobuto_inv_assets | 1 | _state | 1 | _state | A | 4 | NULL | NULL | | BTREE | | |
+-------------------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
中向列site
添加了索引(执行速度降低了近半秒)mobuto_inv_assets
。格式化查询时可能会丢失。当然应该和快速的一样nextinsp
加入,因为它未在那里使用(另外保存2秒)并更新了其saveuser
(删除了最后一行) EXPLAIN
已添加
SHOW INDEX FROM mobuto_inv_sites
答案 0 :(得分:0)
您的第一个查询是使用密钥少于第二个查询。解释计划中的possible_keys
列显示了可以使用密钥的位置,但key
列显示了它们实际使用的位置。
我建议,除了查看数据库的结构之外,还要在JOIN和WHERE子句中更多地使用这些键来加快它的速度。
我们确定当您说您正在修改选择列并且速度不同时,查询不会被缓存。
答案 1 :(得分:0)
12秒首次查询可能是由ROWS列线索引起的,仅考虑24857 * 3 * 915 * 1 = 68,232,465总行数。第二次查询ROWS列的线索不到1秒,仅考虑24857 * 1 * 915 * 1 = 22,744,155总行数。第一个查询使用块嵌套循环处理是延迟响应的主要因素 请发布SHOW CREATE TABLE mobuto_inv_assets和mobuto_inv_sites的结果。还请发布SHOW INDEX FROM mobuto_inv_assets和mobuto_inv_sites的结果。有了这些附加信息,有人可能会建议对SELECT ....查询进行改进,这些查询将避免块嵌套循环处理,这是RBAR(通过Agonizing Row处理行)的时间。可能需要额外的索引。
答案 2 :(得分:0)
感谢您发布两个SHOW CREATE TABLE,非常有帮助。 请考虑添加索引 ALTER TABLE mobuto_inv_sites ADD INDEX网站 - 如果您的系统允许空间。 此外,query1显示的EXPLAIN与查询不匹配。 查询没有引用我在EXPLAIN中可以看到的nextinsp或saveused。 当您有机会再次测试并指示所需的执行时间减少时,请在创建索引后替换EXPLAIN for query1。 如果您可以发布结果也很好 显示来自mobuto_inv_sites的索引,以便我们可以看到您的数据和基数的范围。
答案 3 :(得分:0)
如果使用ACCURATE _state数据填充inv_assets行
考虑将query1更改为以下内容:
选择inv_assets
。id
AS id
,site
。description
AS sitename
,
(选择COALESCE(DATE_FORMAT(CONVERT_TZ(MIN(激励),' UTC'欧洲/维也纳'),'%Y-%m-%d') '&#39)
来自mobuto_inv_inspections
AS nextinsp
WHERE((nextinsp
。objectlink
= inv_assets
。id
和nextinsp
。inspdate
> = NOW()))
)AS nextinsp
来自mobuto_inv_assets
AS inv_assets
在哪里inv_assets
。_state
= 2或inv_assets
。_state
= 0
LEFT JOIN mobuto_inv_sites
AS site
开(site
。siteid
= inv_assets
。site
和site
。_state
IN(2,0))
ORDER BY inv_assets
。type
ASC LIMIT 0,20;
EXPLAIN应避免表扫描和后续的块嵌套循环处理。
如果inv_assets中的_state数据在每一行都不是ACCURATE,那么这将不起作用。
2017-08-10 update 09:42 CT请为所涉及的表发布QUERY,EXPLAIN结果,SHOW CREATE TABLE tblname,并为所涉及的表显示来自tblname的索引。