Cri*_*eak 5 mysql sql query-optimization
我一直在测试不同的想法,以优化我们在工作中的系统中的一些表.今天我遇到了一张桌子,它跟踪我们系统中每辆车的每个视图.在下面创建表格.
SHOW CREATE TABLE vehicle_view_tracking;
CREATE TABLE `vehicle_view_tracking` (
`vehicle_view_tracking_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`public_key` varchar(45) NOT NULL,
`vehicle_id` int(10) unsigned NOT NULL,
`landing_url` longtext NOT NULL,
`landing_port` int(11) NOT NULL,
`http_referrer` longtext,
`created_on` datetime NOT NULL,
`created_on_date` date NOT NULL,
`server_host` longtext,
`server_uri` longtext,
`referrer_host` longtext,
`referrer_uri` longtext,
PRIMARY KEY (`vehicle_view_tracking_id`),
KEY `vehicleViewTrackingKeyCreatedIndex` (`public_key`,`created_on_date`),
KEY `vehicleViewTrackingKeyIndex` (`public_key`)
) ENGINE=InnoDB AUTO_INCREMENT=363439 DEFAULT CHARSET=latin1;
Run Code Online (Sandbox Code Playgroud)
我正在玩多列和单列索引.我运行了以下查询:
EXPLAIN EXTENDED SELECT dealership_vehicles.vehicle_make, dealership_vehicles.vehicle_model, vehicle_view_tracking.referrer_host, count(*) AS count
FROM vehicle_view_tracking
LEFT JOIN dealership_vehicles
ON dealership_vehicles.dealership_vehicle_id = vehicle_view_tracking.vehicle_id
WHERE vehicle_view_tracking.created_on_date >= '2011-09-07' AND vehicle_view_tracking.public_key IN ('ab12c3')
GROUP BY (dealership_vehicles.vehicle_make) ASC , dealership_vehicles.vehicle_model, referrer_host
+----+-------------+-----------------------+--------+----------------------------------------------------------------+------------------------------------+---------+----------------------------------------------+-------+----------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------------------+--------+----------------------------------------------------------------+------------------------------------+---------+----------------------------------------------+-------+----------+----------------------------------------------+
| 1 | SIMPLE | vehicle_view_tracking | range | vehicleViewTrackingKeyCreatedIndex,vehicleViewTrackingKeyIndex | vehicleViewTrackingKeyCreatedIndex | 50 | NULL | 23086 | 100.00 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | dealership_vehicles | eq_ref | PRIMARY | PRIMARY | 8 | vehicle_view_tracking.vehicle_id | 1 | 100.00 | |
+----+-------------+-----------------------+--------+----------------------------------------------------------------+------------------------------------+---------+----------------------------------------------+-------+----------+----------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
(实际选择查询的执行时间为.309秒)
然后我将where子句中的日期从"2011-09-07"更改为"2011-07-07",并得到以下解释结果
EXPLAIN EXTENDED SELECT dealership_vehicles.vehicle_make, dealership_vehicles.vehicle_model, vehicle_view_tracking.referrer_host, count(*) AS count
FROM vehicle_view_tracking
LEFT JOIN dealership_vehicles
ON dealership_vehicles.dealership_vehicle_id = vehicle_view_tracking.vehicle_id
WHERE vehicle_view_tracking.created_on_date >= '2011-07-07' AND vehicle_view_tracking.public_key IN ('ab12c3')
GROUP BY (dealership_vehicles.vehicle_make) ASC , dealership_vehicles.vehicle_model, referrer_host
+----+-------------+-----------------------+--------+----------------------------------------------------------------+-----------------------------+---------+----------------------------------------------+-------+----------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------------------+--------+----------------------------------------------------------------+-----------------------------+---------+----------------------------------------------+-------+----------+----------------------------------------------+
| 1 | SIMPLE | vehicle_view_tracking | ref | vehicleViewTrackingKeyCreatedIndex,vehicleViewTrackingKeyIndex | vehicleViewTrackingKeyIndex | 47 | const | 53676 | 100.00 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | dealership_vehicles | eq_ref | PRIMARY | PRIMARY | 8 | vehicle_view_tracking.vehicle_id | 1 | 100.00 | |
+----+-------------+-----------------------+--------+----------------------------------------------------------------+-----------------------------+---------+----------------------------------------------+-------+----------+----------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
(实际选择查询的执行时间为.670秒)
我看到4个主要变化:
此时,慢速查询的执行时间仅为0.6秒,但我们的数据库中只有大约10%的车辆.
它已经很晚了,我可能忽略了mysql文档中的一些内容,但我似乎无法找到为什么在where子句中更改日期时键(以及类型和行)正在发生变化.
非常感谢帮助.我搜索了具有相同/类似问题的人,导致此更改的日期并且无法找到任何内容.如果我错过了以前的帖子,请链接我:-)
不同的搜索策略对不同的数据有意义.特别是,索引扫描(例如范围)通常必须寻求实际读取行.在某些时候,做所有这些搜索比完全不使用索引要慢.
举一个简单的例子,一个包含三列的表:id(主键),name(索引),birthday.说它有很多数据.如果你要求MySQL寻找Bob的生日,它可以相当快地做到这一点:首先,它在名称索引中找到Bob(这需要一些搜索,log(n),其中n是行数),然后另外一个寻求读取数据文件中的实际行并从中读取生日.这比扫描整个桌子快得多,速度也快得多.
接下来,考虑做一个name like 'Z%'.这可能只是表格的一小部分.因此,更快地找到Zs在名称索引中的起始位置,然后为每一个寻找数据文件来读取行.(这是范围扫描).
最后,考虑询问所有以MZ开头的名字.这可能是数据的一半左右.它可以进行范围扫描,然后进行大量搜索,但是在数据文件中随机搜索,最终目标是读取一半行不是最佳的:只需对数据文件进行大量顺序读取就会更快.因此,在这种情况下,索引将被忽略.
这就是你所看到的 - 除了在你的情况下,还有另一个可以依赖的关键.(它也可能实际上使用日期索引,如果没有另一个,它应该选择哪个索引最快.请注意MySQL的优化器经常会出错.)
所以,简而言之,这是预期的.查询没有说明如何检索数据,而是说要检索哪些数据.数据库的优化器应该找到最快的方法来检索它.
您可以在两个列中找到索引,在这两种情况下都是首选(public_key,created_on_date),并加快查询速度.这是因为MySQL每个表只能使用一个索引(每个查询).此外,日期结束,因为范围扫描只能在索引的最后一列上有效地完成.
[InnoDB实际上有另一层间接,我相信,但它只是混淆了这一点.它对解释没有任何影响.]
| 归档时间: |
|
| 查看次数: |
7650 次 |
| 最近记录: |