coh*_*hoz 3 mysql performance index query-performance
我有一个跨两个大表的查询。第一个记录了一个位置的最新用户活动,第二个是一个带有位置自然主键的维度表。
这里的表大小大约为 1 亿行 inuser_location_rating
和 1000 万行 in dim_location
. 大多数用户有 < 1000 条记录user_location_rating
,对于这些用户来说,查询性能已经足够了。
对于有大量活动数据的用户,这个查询,即使是两个简单的选择,仍然会很慢。我想提高查询性能。这可以通过添加额外的索引来完成吗?作为替代方案,有没有一种方法可以利用索引使有限的查询(如下)比完整查询更有效?
SELECT d.create_time
FROM user_location_rating f
JOIN dim_location d using(location_id)
WHERE f.user_id=?
AND f.platform=?
AND d.category=?;
SELECT d.create_time
FROM user_location_rating f
JOIN dim_location d using(location_id)
WHERE f.user_id=?
AND f.platform=?
AND d.category=?
ORDER BY d.create_time DESC
LIMIT 1000;
Run Code Online (Sandbox Code Playgroud)
EXPLAIN SELECT 对这些查询产生以下结果(例如,对于具有 999 个事件的用户)
+----+-------------+----------------------+--------+-------------------------------+-----------+---------+----------------------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+--------+-------------------------------+-----------+---------+----------------------------------+------+-------------+
| 1 | SIMPLE | user_location_rating | ref | k_userloc,k_locplat,k_usrplat | k_usrplat | 8 | const,const | 999 | Using index |
| 1 | SIMPLE | dim_location | eq_ref | PRIMARY | PRIMARY | 4 | user_location_rating.location_id | 1 | Using where |
+----+-------------+----------------------+--------+-------------------------------+-----------+---------+----------------------------------+------+-------------+
+----+-------------+----------------------+--------+-------------------------------+-----------+---------+----------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+--------+-------------------------------+-----------+---------+----------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | user_location_rating | ref | k_userloc,k_locplat,k_usrplat | k_usrplat | 8 | const,const | 999 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | dim_location | eq_ref | PRIMARY | PRIMARY | 4 | user_location_rating.location_id | 1 | Using where |
+----+-------------+----------------------+--------+-------------------------------+-----------+---------+----------------------------------+------+----------------------------------------------+
Run Code Online (Sandbox Code Playgroud)
表定义
CREATE TABLE `user_location_rating` (
`user_activity_id` int(16) NOT NULL AUTO_INCREMENT,
`user_id` int(16) NOT NULL DEFAULT '0',
`location_id` int(16) NOT NULL DEFAULT '0',
`platform` int(2) NOT NULL DEFAULT '-1',
`rating` int(2) NOT NULL DEFAULT '-1'
PRIMARY KEY (`location_id`,`user_activity_id`),
UNIQUE KEY `k_userloc` (`user_id`,`location_id`),
KEY `k_locplat` (`location_id`,`platform`),
KEY `k_usrplat` (`user_id`,`platform`)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC
CREATE TABLE `dim_location` (
`location_id` int(16) NOT NULL AUTO_INCREMENT,
`category` int(2) NOT NULL DEFAULT '0',
`create_time` datetime DEFAULT NULL,
PRIMARY KEY (`location_id`)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC
Run Code Online (Sandbox Code Playgroud)
(我已经做了一些努力来清理这里的实际定义,以接近最小的相关示例,因此如果出现任何拼写错误,我深表歉意。)
对于第一个表,两个查询都最好在(platform, user_id, location_id)
or上建立索引(user_id, platform, location_id)
。对您有好处,现有索引k_usrplat
相当于第二个索引(InnoDB 索引默默地包含 PK 列)。可以看到两个查询确实都使用了该索引。
对于第二个表,它更复杂。您可能会使用主键的现有索引获得足够的性能,至少对于第一次查询。一个可能的改进是(category, location_id, create_time)
索引。
您也可以尝试使用(category, create_time, location_id)
索引,这可能对第二个查询有用。很大程度上取决于数据的分布,不同参数的效率可能会有所不同。
整数列的定义看起来很奇怪。为什么你有int (16)
和int (2)
?如果您认为这意味着对列中可能的值有任何限制,那您就错了。列的类型相同,括号中的数字只是对用户界面的指示,通常被忽略。例如,如果其中一些列platform
只能包含较小的值(例如 0-100 或 0-2000),则使用适当较小的类型:
tiny int (-128 .. +127) : 1 byte
small int (-32768 .. + 32767) : 2 bytes
medium int (-2^23 .. + 2^23-1) : 3 bytes
tiny int unsigned (0 .. +255) : 1 byte
small int unsigned (0 .. +65535) : 2 bytes
medium int unsigned (0 .. +2^24-1) : 3 bytes
Run Code Online (Sandbox Code Playgroud)
这将节省表及其索引中的空间,包括磁盘和内存使用量。
更少的空间 -> 更少的 I/O -> 更快的查询
归档时间: |
|
查看次数: |
763 次 |
最近记录: |