我在 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"
仅使用复合索引的第一列。 col2
和col3
的约束使用表扫描进行评估。
有人可以向我解释这里发生了什么,并提出如何改进的建议吗?
我目前通过将列合并到一列来解决它,方法是引入并索引连接col1
和col2
的已存储生成列。但是,我不能将此用于想要在这些列上使用IN()
运算符的查询。
提前谢谢!
亚诺
答案 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"
ANDs
中WHERE
的顺序无关紧要。
INDEX
中列的顺序很重要。首先INDEX
col1
和col3
,无论是哪种顺序,都会更好。
在比较INDEX(col1)
与INDEX(col3)
时,基数确实很重要。
对于实际使用的索引部分,基数确实不,就像比较INDEX(col1, col3)
与INDEX(col3, col1)
时一样。
相比之下,WHERE int_col = "123"
将转换为"123"
到123
能够使用索引。
答案 2 :(得分:0)
谢谢大家的回复。在使用索引中的列顺序(与基数相关)之后,我注意到应用程序正在与col2
上的整数值进行比较(这是一个varchar列)。将值转换为字符串可解决性能问题。