我下面有一张桌子
CREATE TABLE `xcpRush2_SandraTriplets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`idConceptStart` int(11) NOT NULL,
`idConceptLink` int(11) NOT NULL,
`idConceptTarget` int(11) NOT NULL,
`flag` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_name` (`idConceptStart`,`idConceptLink`,`idConceptTarget`),
KEY `idConceptStart` (`idConceptStart`,`idConceptLink`,`idConceptTarget`),
KEY `idConceptStart_4` (`idConceptStart`),
KEY `idConceptTarget` (`idConceptTarget`),
KEY `idConceptLink` (`idConceptLink`,`idConceptTarget`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
数据看起来像数据库小提琴:https://www.db-fiddle.com/f/ejXP7qgvwNqAZeuaN3DFNz/3
如您所见,它已在几列上完全索引。
在我的桌子上,我有大约80万个idConceptStart满足满足
的条件idConceptLink = 5 idConceptTarget = 14500 AND
idConceptLink = 3 idConceptLink = 14504 AND
idConceptLink = 12 idConceptLink = 11
执行此查询时
SELECT * FROM xcpRush2_SandraTriplets l
JOIN xcpRush2_SandraTriplets link1 ON link1.idConceptStart = l.idConceptStart
JOIN xcpRush2_SandraTriplets link2 ON link2.idConceptStart = link1.idConceptStart
WHERE
l.idConceptLink = 5 AND
l.idConceptTarget = 14500 AND
l.flag != 1 AND
link2.flag != 1 AND
link2.idConceptLink = 3 AND
link2.idConceptTarget = 14504 AND
link1.flag != 1 AND
link1.idConceptTarget = 12 AND
l.idConceptLink = 11
ORDER BY l.idConceptStart DESC LIMIT 10
查询大约需要30秒(!)呈现
但是如果我删除了这个(并且只有这个)
link2.idConceptLink = 3 AND link2.idConceptTarget =14504
然后查询需要20毫秒的时间呈现
SELECT * FROM xcpRush2_SandraTriplets l
JOIN xcpRush2_SandraTriplets link1 ON link1.idConceptStart = l.idConceptStart
JOIN xcpRush2_SandraTriplets link2 ON link2.idConceptStart = l.idConceptStart
WHERE
l.idConceptLink = 5 AND
l.idConceptTarget = 14500 AND
l.flag != 1 AND
link2.flag != 1 AND
link1.flag != 1 AND
link1.idConceptTarget = 12 AND
link1.idConceptLink = 11
ORDER BY l.idConceptStart DESC LIMIT 10
我很困惑,因为该表在idConceptLink
,idConceptTarget
上建立了索引,并且分别进行的每个查询都非常快地呈现了<20 ms
查询中的每对idConceptLink
,idConceptTarget
对都返回大量行(不仅link2.idConceptLink = 3 AND link2.idConceptTarget = 14504)
您能帮我确定瓶颈吗?
修改
在评论中发现更多问题后,问题似乎在ORDER BY上。取决于我是否加入l.idConceptStart或link1.idConceptStart或link2.idConceptStart,查询速度很慢。在我的实际情况下,ORDER BY link2.idConceptStart 很慢。
索引结构如下
CREATE TABLE `xcpRush2_SandraTriplets` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`idConceptStart` int(11) NOT NULL,
`idConceptLink` int(11) NOT NULL,
`idConceptTarget` int(11) NOT NULL,
`flag` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_name` (`idConceptStart`,`idConceptLink`,`idConceptTarget`),
KEY `idConceptStart` (`idConceptStart`),
KEY `idConceptTarget` (`idConceptTarget`),
KEY `idConceptLink` (`idConceptLink`,`idConceptTarget`)
) ENGINE=InnoDB AUTO_INCREMENT=5747878 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
索引是
xcprush2_sandratriplets 0 PRIMARY 1 id A 5207892 NULL NULL BTREE
xcprush2_sandratriplets 0 idx_name 1 idConceptStart A 1243366 NULL NULL BTREE
xcprush2_sandratriplets 0 idx_name 2 idConceptLink A 5207936 NULL NULL BTREE
xcprush2_sandratriplets 0 idx_name 3 idConceptTarget A 5207936 NULL NULL BTREE
xcprush2_sandratriplets 1 idConceptStart 1 idConceptStart A 1122352 NULL NULL BTREE
xcprush2_sandratriplets 1 idConceptTarget 1 idConceptTarget A 123870 NULL NULL BTREE
xcprush2_sandratriplets 1 idConceptLink 1 idConceptLink A 5 NULL NULL BTREE
xcprush2_sandratriplets 1 idConceptLink 2 idConceptTarget A 154480 NULL NULL BTREE
查询时慢
SELECT l.idConceptStart, l.idConceptLink, l.`idConceptTarget` FROM xcpRush2_SandraTriplets l JOIN xcpRush2_SandraTriplets link1 ON link1.idConceptStart = l.idConceptStart JOIN xcpRush2_SandraTriplets link2 ON link2.idConceptStart = l.idConceptStart
WHERE l.idConceptLink = 5
AND l.idConceptTarget = 14500
AND l.flag != 1
AND link1.flag != 1 AND
link1.idConceptTarget =14504 AND link1.idConceptLink = 3 AND link2.flag != 1 AND
link2.idConceptTarget =12 AND link2.idConceptLink = 11 ORDER BY link2.idConceptStart DESC LIMIT 1000 OFFSET 0
这里是EXPLAIN结构
1 SIMPLE link1 NULL ref idx_name,idConceptStart,idConceptTarget,idConceptLink idConceptTarget 4 const 1611256 18.00 Using where; Using temporary; Using filesort
1 SIMPLE l NULL eq_ref idx_name,idConceptStart,idConceptTarget,idConceptLink idx_name 12 sandra.link1.idConceptStart,const,const 1 90.00 Using where
1 SIMPLE link2 NULL eq_ref idx_name,idConceptStart,idConceptTarget,idConceptLink idx_name 12 sandra.link1.idConceptStart,const,const 1 90.00 Using where
查询时快速
SELECT l.idConceptStart, l.idConceptLink, l.`idConceptTarget` FROM xcpRush2_SandraTriplets l JOIN xcpRush2_SandraTriplets link1 ON link1.idConceptStart = l.idConceptStart JOIN xcpRush2_SandraTriplets link2 ON link2.idConceptStart = l.idConceptStart
WHERE l.idConceptLink = 5
AND l.idConceptTarget = 14500
AND l.flag != 1
AND link1.flag != 1 AND
link1.idConceptTarget =14504 AND link1.idConceptLink = 3 AND link2.flag != 1 AND
link2.idConceptTarget =12 AND link2.idConceptLink = 11 ORDER BY l.idConceptStart DESC LIMIT 1000 OFFSET 0
这里是EXPLAIN结构
1 SIMPLE l NULL index idx_name,idConceptStart,idConceptTarget,idConceptLink idConceptStart 4 NULL 13036 3.08 Using where
1 SIMPLE link1 NULL eq_ref idx_name,idConceptStart,idConceptTarget,idConceptLink idx_name 12 sandra.l.idConceptStart,const,const 1 90.00 Using where
1 SIMPLE link2 NULL eq_ref idx_name,idConceptStart,idConceptTarget,idConceptLink idx_name 12 sandra.l.idConceptStart,const,const 1 90.00 Using where
编辑2
排序的最佳表似乎是随机的。现在,我几个小时后运行了相同的查询(发生了一些插入),但是使用相同的查询,解决键顺序的结构发生了变化。快速查询变成慢查询,而慢查询变成快速查询。如果我通过l.idConcept订购,请进行以下解释
键的表解析顺序似乎是随机的。我完全迷路了。最后,我唯一需要的就是首先获取最后一个数据库条目
答案 0 :(得分:1)
“完全索引”-不。您有一些索引,包括一些多余的索引。
这可能是查询的最佳索引:
INDEX(link, target, start)
让我们谈谈flag
。它有多少个不同的值?如果只有2(例如0和1),则更改为flag = 0
而不是flag != 1
。与=
相比,Optimizer更适合处理!=
测试。并更改为INDEX(link, target, flag, start)
。
有百分之几的行具有flag = 1?这可能会引起更多想法。
您有UNIQUE
键和代理人id
吗?您是否从其他任何表中引用了id
?如果不是,请摆脱它,并将UNIQUE
提升为PRIMARY KEY
。但是到那时,我希望重新排列该PK中的列以符合我的建议。
一些建立索引的规则:
=
(以link
和target
(以任意顺序)进行测试的列WHERE
列,最好让索引完全处理!=
(ORDER BY
正在停止该索引)( s)。如果还存在LIMIT
,则尤其如此。UNIQUE(a,b,c)
排除了对INDEX(a,b,c)
的需求INDEX(a,b)
排除了对INDEX(a)
的需求。答案 1 :(得分:0)
通过使用 通过l.idConceptStart DESC命令 而不是 ORDER BY link2.idConceptStart DESC 您可以避免每次解释临时存储和文件排序 并且可以减少访问的ROWS。
查看我的个人资料,网络个人资料以获取联系信息。