MySQL没有使用复合索引的所有关键部分

时间:2018-05-14 08:22:04

标签: mysql performance indexing composite-key

我在 MySQL 5.7.19 中有一个包含~1.7m行的InnoDB表。我想优化以下查询:

select * from `table` where `col1` = 'x' and `col2` = 123 and `col3` = 'z'

其中列定义为(全部使用utf8mb4编码):

col1 varchar(255) null
col2 varchar(255) not null
col3 varchar(255) not null

和所有列的索引:

key (
  col1, -- Cardinality: 40
  col2, -- Cardinality: 472810
  col3  -- Cardinality: 403767
)

我希望查询运行得很快,因为MySQL应该能够充分利用索引。现在,性能不是很好,当我使用explain format=json运行查询时它开始变得有意义了:

"used_key_parts": [
   "col1"
],
"key_length": "1022"

仅使用复合索引的第一列。 col2col3的约束使用表扫描进行评估。

有人可以向我解释这里发生了什么,并提出如何改进的建议吗?

我目前通过将列合并到一列来解决它,方法是引入并索引连接col1col2的已存储生成列。但是,我不能将此用于想要在这些列上使用IN()运算符的查询。

提前谢谢!

亚诺

3 个答案:

答案 0 :(得分:1)

尝试使用高基数列构建复合

例如:

unique_label = np.unique(y_true)
print(pd.DataFrame(confusion_matrix(y_true, y_pred, labels=unique_label), 
                   index=['true:{:}'.format(x) for x in unique_label], 
                   columns=['pred:{:}'.format(x) for x in unique_label]))
# Output:
#           pred:no  pred:yes
# true:no         3         0
# true:yes        2         1

并且确实使用了AND运算符,而不需要()aroudn条件

col2,col3,col1 

最后你可以用FORCE

强加索引

答案 1 :(得分:1)

`col2` = 123

是你的撤消。将VARCHAR与整数常量进行比较时,varchar将转换为numeric。这需要动态转换所有相关行。

毕竟,col2可以包含"0123""123.0""1.23e2"。作为弦乐,那些是完全不同的; varchars上的索引根据 string 属性(COLLATION)进行排序。

可能的解决方案是更改为添加引号:

`col2` = "123"

ANDsWHERE的顺序无关紧要。

INDEX中列的顺序很重要。首先INDEX col1col3,无论是哪种顺序,都会更好。

在比较INDEX(col1)INDEX(col3)时,基数确实很重要。

对于实际使用的索引部分,基数确实,就像比较INDEX(col1, col3)INDEX(col3, col1)时一样。

相比之下,WHERE int_col = "123" 转换为"123"123能够使用索引。

答案 2 :(得分:0)

谢谢大家的回复。在使用索引中的列顺序(与基数相关)之后,我注意到应用程序正在与col2上的整数值进行比较(这是一个varchar列)。将值转换为字符串可解决性能问题。