数据库
首页 > 数据库> > mysql – 使用limit和index提高连接查询性能

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