由于生产问题,我一直在运行mysql的慢速登录,而第一个查询是:
select * from feeditem feeditem0_ where feeditem0_.importance=0 and feeditem0_.company_id=N limit 21;
我将select(N是一个id到fK)缩写为从hibernate生成的,只是选择该表中的所有字段。当我做一个mysql解释时,我得到:
explain select * from feeditem feeditem0_ where feeditem0_.importance=0 and feeditem0_.company_id=5045 limit 21 \G;;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: feeditem0_
type: index_merge
possible_keys: FKF49961B13D5FD8EF,importance
key: FKF49961B13D5FD8EF,importance
key_len: 9,5
ref: NULL
rows: 2422
Extra: Using intersect(FKF49961B13D5FD8EF,importance); Using where
该表中有大约850K行。
架构是:
CREATE TABLE `feeditem` (
`DTYPE` varchar(31) NOT NULL,
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`dateCreated` datetime DEFAULT NULL,
`endSentance` varchar(255) DEFAULT NULL,
`importance` int(11) DEFAULT NULL,
`startSentance` varchar(255) DEFAULT NULL,
`summary` varchar(255) DEFAULT NULL,
`summaryComplete` bit(1) NOT NULL,
`targetId` bigint(20) DEFAULT NULL,
`targetSentance` text,
`type` varchar(255) NOT NULL,
`hasRead` bit(1) DEFAULT NULL,
`teamProject_id` bigint(20) DEFAULT NULL,
`user_id` bigint(20) DEFAULT NULL,
`usertoread_id` bigint(20) DEFAULT NULL,
`contentType` varchar(255) DEFAULT NULL,
`company_id` bigint(20) DEFAULT NULL,
`updated` int(1) unsigned DEFAULT NULL,
`feedType` varchar(255) DEFAULT NULL,
`extraInfo` varchar(255) DEFAULT NULL,
`extraTargetId` bigint(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FKF49961B1B74A2DA5` (`user_id`),
KEY `FKF49961B17CE9E5EF` (`teamProject_id`),
KEY `FKF49961B137B7D1B4` (`usertoread_id`),
KEY `FKF49961B13D5FD8EF` (`company_id`),
KEY `importance` (`importance`),
KEY `dateCreated` (`dateCreated`)
) ENGINE=InnoDB AUTO_INCREMENT=956498 DEFAULT CHARSET=utf8
有没有办法阻止扫描2400多行?这是慢速日志(使用mysqlsla)的摘要:
Count : 61 (53.98%)
Time : 523 s total, 8.57377 s avg, 6 s to 19 s max (54.03%)
95% of Time : 456 s total, 8 s avg, 6 s to 14 s max
Lock Time (s) : 0 total, 0 avg, 0 to 0 max (0.00%)
95% of Lock : 0 total, 0 avg, 0 to 0 max
Rows sent : 34 avg, 21 to 51 max (38.69%)
Rows examined : 3.49k avg, 40 to 8.89k max (0.00%)
Users :100.00% (61) of query, 100.00% (113) of all users
感谢
UPDATE 1:我添加了另一个2 col索引(称为feedquery),但似乎优化器选择不使用索引:
mysql> explain select id from feeditem feeditem0_ where feeditem0_.importance=0 and feeditem0_.company_id=5045 \G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: feeditem0_
type: index_merge
possible_keys: FKF49961B13D5FD8EF,importance,feedquery
key: FKF49961B13D5FD8EF,feedquery
key_len: 9,14
ref: NULL
rows: 2753
Extra: Using intersect(FKF49961B13D5FD8EF,feedquery); Using where; Using index
如果我忽略索引:
explain select id from feeditem feeditem0_ ignore index (FKF49961B13D5FD8EF) where feeditem0_.importance=0 and feeditem0_.company_id=5045 \G;
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: feeditem0_
type: ref
possible_keys: importance,feedquery
key: feedquery
key_len: 14
ref: const,const
rows: 8496
Extra: Using where; Using index
表格:
CREATE TABLE `feeditem` (
.....
PRIMARY KEY (`id`),
KEY `FKF49961B1B74A2DA5` (`user_id`),
KEY `FKF49961B17CE9E5EF` (`teamProject_id`),
KEY `FKF49961B137B7D1B4` (`usertoread_id`),
KEY `FKF49961B13D5FD8EF` (`company_id`),
KEY `importance` (`importance`),
KEY `dateCreated` (`dateCreated`),
KEY `feedquery` (`importance`,`company_id`)
) ENGINE=InnoDB AUTO_INCREMENT=999359 DEFAULT CHARSET=utf8
更新2: @Salman A
SHOW profile;
+----------------------+----------+
| Status | Duration |
+----------------------+----------+
| starting | 0.000342 |
| checking permissions | 0.000024 |
| Opening tables | 0.000053 |
| System lock | 0.000027 |
| init | 0.000166 |
| optimizing | 0.000068 |
| statistics | 0.012869 |
| preparing | 0.000202 |
| executing | 0.000008 |
| Sending data | 0.332767 |
| end | 0.000022 |
| query end | 0.000009 |
| closing tables | 0.000016 |
| freeing items | 0.000040 |
| logging slow query | 0.000005 |
| cleaning up | 0.000014 |
+----------------------+----------+
ibdata1大约是1.5 GB
答案 0 :(得分:5)
一般答案:
SELECT *
。选择您只需要的列。ORDER BY
条款或LIMIT
不会太有意义。importance
和company_id
ORDER BY
的字段,按预期顺序SELECT
返回的任何其他字段(代替*
)这样,数据库引擎可以使用单个索引查找操作查找与搜索的直接匹配,并直接从索引中覆盖排序和其他列。索引包含它涵盖的所有列的副本;如果所有请求的数据都驻留在索引中,则无需通过实际的表。这将提高查询效率。
请注意,这是一种速度换空间。您添加到索引的每一列都会增加其物理大小,因此请明智地选择。
编辑1:此外,索引会影响写操作的速度 - 由于索引维护,INSERT,UPDATE和DELETE查询会慢一些 - 以换取SELECT更快。 (感谢评论,@ Thor84no)
编辑2:如果此查询是表和的主要使用模式,那么表变化不大(这一点非常重要!),您可以考虑创建聚簇索引。聚簇索引表示基表的物理排序,除了基表之外不存在,就像其他索引一样。每次更改聚簇索引的定义或添加/删除“中间”现有记录的行时,实际数据都会在物理上重新排序,即在磁盘上,这是一项您想要避免的昂贵操作。
有时候这可能是一件明智的事情,但在你的情况下,它可能不是。如果您的表是某些类别的日志表,请将聚集索引保留为自动递增ID。
答案 1 :(得分:2)
标准select x from y where z
(这是您拥有的,只有多个条件)是您可以运行的最有效的查询之一。您唯一可以添加的是包含您查询的所有列的索引;但是,这会影响写入此表时的性能。 (以及第一次填充所述指数的高位一击)。
如果您知道查询中的某个列会比其他列限制结果,那么您可以进行折衷,只在该查询上添加索引。例如。如果只查找带有company_id = x的行,则可以保证只剩下几行来过滤掉,那么只有该列的索引可能更合适。
答案 2 :(得分:1)
基本上,由于每个索引只包含WHERE子句中引用的两个字段之一,因此引擎需要获取满足第一部分的记录和满足第二部分的记录(通过使用索引“importance”和“FKF49961B13D5FD8EF”,分别)。
索引生成的简单规则是,您希望索引看起来与WHERE子句中的字段完全相同。因此,您可以按此顺序使用“importance”和“company_id”创建索引。这将精确选择匹配的行,并且不再扫描2.4k行。