mysql – 使用limit和index提高连接查询性能
作者:互联网
我有两个大表的查询.第一个记录位置的最新用户活动,第二个是具有位置的自然主键的维度表.
这里的表大小在user_location_rating中大约是1亿行,在dim_location中是1000万行.
大多数用户拥有< user_location_rating中的1000条记录以及那些用户查询性能就足够了.
对于具有大量活动数据的用户,此查询即使是两个简单的选择,仍然可能很慢.
我想提高查询性能.可以通过添加额外的索引来完成吗?
作为替代方案,是否有一种方法可以利用索引来使查询(例如下面)比完整查询更有效?
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;
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 |
+----+-------------+----------------------+--------+-------------------------------+-----------+---------+----------------------------------+------+----------------------------------------------+
表定义
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
(我已经做了一些努力来清理这里的实际定义,以便接近最小的相关示例,所以如果有任何拼写错误,请道歉.)
解决方法:
对于第一个表,两个查询的(platform,user_id,location_id)或(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
这将节省磁盘和内存使用中的表及其索引的空间.
空间更小 – >减少I / O – >更快的查询
标签:query-performance,mysql,index 来源: https://codeday.me/bug/20190806/1600486.html