这是表结构:
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| visitor_hash | varchar(40) | YES | MUL | NULL | |
| uri | varchar(255) | YES | | NULL | |
| ip_address | char(15) | YES | MUL | NULL | |
| last_visit | datetime | YES | | NULL | |
| visits | int(11) | NO | | NULL | |
| object_app | varchar(255) | YES | MUL | NULL | |
| object_model | varchar(255) | YES | | NULL | |
| object_id | varchar(255) | YES | | NULL | |
| blocked | tinyint(1) | NO | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
这是请求:
SELECT `object_id`
FROM `visits_visit`
WHERE `object_model` = 'News'
GROUP BY `object_id`
ORDER BY COUNT( * ) DESC
LIMIT 0, 3
响应时间约为77,63毫秒。
CREATE INDEX resource_model ON visits_visit (object_model(100));
在此请求之后,响应时间增加到~150ms。
如何提高此案例的效果?谢谢。
更新:
回答Michal Komorowski。 这在索引之前解释:
+----+-------------+--------------+------+---------------+------+---------+------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+------+---------------+------+---------+------+--------+----------------------------------------------+
| 1 | SIMPLE | visits_visit | ALL | NULL | NULL | NULL | NULL | 142938 | Using where; Using temporary; Using filesort |
+----+-------------+--------------+------+---------------+------+---------+------+--------+----------------------------------------------+
1 row in set (0.00 sec)
这是在索引之后:
+----+-------------+--------------+------+----------------+----------------+---------+-------+-------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------+------+----------------+----------------+---------+-------+-------+----------------------------------------------+
| 1 | SIMPLE | visits_visit | ref | resource_model | resource_model | 303 | const | 64959 | Using where; Using temporary; Using filesort |
+----+-------------+--------------+------+----------------+----------------+---------+-------+-------+----------------------------------------------+
1 row in set (0.00 sec)
我不知道是什么给了我这个信息。
SELECT `object_id`
FROM `visits_visit`
WHERE `object_model` = 'News'
GROUP BY `object_id`
ORDER BY COUNT( * ) DESC
LIMIT 0, 3
索引前78,85 ms,索引后365,59 ms。
我也有索引
CREATE INDEX resource ON visits_visit (object_app(100), object_model(100), object_id(100));
但是我需要这个,因为在其他选择查询中,WHERE包含这三个键。
更新
我正在使用django调试工具栏来测试请求的性能。
更新
查询:
ANALYZE TABLE visits_visit;
输出:
+-----------------------------+---------+----------+-----------------------------+
| Table | Op | Msg_type | Msg_text |
+-----------------------------+---------+----------+-----------------------------+
| **************.visits_visit | analyze | status | Table is already up to date |
+-----------------------------+---------+----------+-----------------------------+
1 row in set (0.00 sec)
更新
SHOW INDEXES FROM visits_visit;
输出:
+--------------+------------+-----------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------------+------------+-----------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| visits_visit | 0 | PRIMARY | 1 | id | A | 142938 | NULL | NULL | | BTREE | | |
| visits_visit | 1 | visits_visit_0880babc | 1 | visitor_hash | A | 142938 | NULL | NULL | YES | BTREE | | |
| visits_visit | 1 | visits_visit_5325a746 | 1 | ip_address | A | 142938 | NULL | NULL | YES | BTREE | | |
| visits_visit | 1 | resource | 1 | object_app | A | 1 | 100 | NULL | YES | BTREE | | |
| visits_visit | 1 | resource | 2 | object_model | A | 3 | 100 | NULL | YES | BTREE | | |
| visits_visit | 1 | resource | 3 | object_id | A | 959 | 100 | NULL | YES | BTREE | | |
+--------------+------------+-----------------------+--------------+--------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
答案 0 :(得分:0)
我对sql机制的误解感到困惑,所以我决定每24小时创建一个模型Popular和save实例。感谢所有试图提供帮助的人。
答案 1 :(得分:0)
在我看来,虽然你有一个索引,MySQL并不知道如何正确使用它。当表中的数据分布(统计)信息不是最新时,就会发生这种情况。要更新它们,您应该致电ANALYZE TABLE visits_visit
,然后检查结果。
答案 2 :(得分:0)
正如我在你的另一个问题中所说,前缀索引几乎没用;除非在极少数情况下,否则不要使用它们。
将字段缩小到合理的长度,您不会想要使用前缀索引。
该查询的最佳索引是INDEX(object_model, object_id)
。尝试使用INDEX(object_model(##), ...)
将不会超过object_model
之后的任何内容。
如果object_model
是'新闻'之类的东西,我怀疑其他可能的值很短,并且可能存在有限数量的模型。对于某些较小的VARCHAR
进行“短暂”更改。对于“有限”,请考虑使用ENUM('News', 'Weather', 'Sports', ...)
。
至于为什么索引后需要更长的时间......
object_id
(不太好)。似乎(从时间上看)后者的效率较低。通过缩小声明并使用INDEX(object_model, object_id)
(按此顺序),可以在索引中执行查询。将索引视为一个迷你表,其中只包含这两列。它更小。它按模型排序,因此只需要扫描“新闻”部分。解释将通过说“使用索引”来显示这种“覆盖”。
如果遇到所有情况,GROUP BY
会增加一些开销 - 要么在RAM中保留object_id
的哈希值,要么保存中间结果并对其进行排序。然后ORDER BY
需要排序(或优先级哈希)才能应用LIMIT
。