我已经阅读了很多有关识别列的主题,这些列可能是创建索引的最佳人选。但是,大多数建议在JOIN或WHERE子句中使用的列上创建索引。
不过,我不确定像下面这样的复杂查询
select b.col1 ,a.col1 ,a.selectionId ,a.table2Id ,a.selectionName ,b.UserId,b.ParantId ,
a.teamType ,d.Name,b.isBack,b.SelectionId,b.Admin AS admin,
b.Master AS master,c.MstDate AS MstDate, c.col2
from tblselection a
join table1 c on c.col1 = a.col1
join table2 d on d.Id = a.table2Id
left join tabletest b on b.SelectionId = a.selectionId and a.table2Id = b.table2Id and b.IsMatched = 1
where ((ifnull(c.active,0) = 1) and isnull(b.Result) and isnull(b.ResultID))
在该查询的所有4个表中,哪个列是索引的最佳选择?
我应该在这里创建复合索引还是单个索引?
答案 0 :(得分:1)
使用查询前面的EXPLAIN
关键字(EXPLAIN SELECT b.cl1, a.col1 ...
)运行查询。 MySQL将为您提供事物之间如何连接以及如何扫描以找出它的行的细目分类。
通常,您要在要引用的列上建立索引,尤其是当它需要查看很多行或使用“表扫描”将它们连接在一起时。您希望它说“使用主”或“使用索引”
这是我的一个数据库的一些示例输出。您可以看到此查询联接了3个表,但是即使表很大,最终还是可以很快找到它。每个子部分仅需要引用一行:
+----+-------------+-------+------------+--------+---------------------+---------+---------+-------------------------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------------+---------+---------+-------------------------------+------+----------+-------------+
| 1 | SIMPLE | sa | NULL | ref | choice_id,user_id | user_id | 5 | const | 1 | 100.00 | Using where |
| 1 | SIMPLE | qc | NULL | eq_ref | PRIMARY,question_id | PRIMARY | 4 | sa.choice_id | 1 | 100.00 | Using where |
| 1 | SIMPLE | q | NULL | eq_ref | PRIMARY | PRIMARY | 4 | qc.question_id | 1 | 100.00 | NULL |
+----+-------------+-------+------------+--------+---------------------+---------+---------+-------------------------------+------+----------+-------------+
答案 1 :(得分:1)
首先,更改
where ((ifnull(c.active,0) = 1)
and isnull(b.Result)
and isnull(b.ResultID))
到
WHERE c.active = 1
AND b.Result IS NULL
AND b.ResultID IS NULL
我怀疑优化器能否很好地处理IFNULL()
。
请提供SHOW CREATE TABLE
和EXPLAIN SELECT...
您现在可能会看到c
是EXPLAIN
中的第一张表。让我们通过提供
c: INDEX(active, col1) -- in that order
之后,
a: INDEX(col1)
d: INDEX(Id) -- unless it is already PRIMARY KEY(Id)
b: INDEX(IsMatched, table2Id, SelectionId) -- in any order
在处理JOIN
时,您需要弄清楚表的顺序。不要信任EXPLAIN
,因为它(最初)不知道您要添加什么索引。
在您的情况下,WHERE
引用了c
和b
。但是b
是LEFT JOIN
,因此我们不能使用它。剩下c
。要索引的唯一有用的列是active
(在重新格式化之后)。但这听起来像是Optimizer避开的简单,低基数的“标志”。我在索引中添加了一些内容,希望优化程序会被欺骗使用它。
那么,“下一个”表将是什么? JOINs
仅从c
到a
。接下来是a
。 JOIN
使用col1
。
下一步可以是d
或b
。看起来,`优化器可以按任意顺序执行它们,并且无论顺序如何,都可以对事物进行相同的优化。
d
:Id
是如何到达它。
b
需要使用简单的ON
检查AND
中的3件事。因此,这3列的“复合”索引可以任意顺序。 (不,每列的“基数”都没有关系,即使选择订单也是如此。)
关于b... IS NULL
子句中的WHERE
测试-大概是在测试LEFT
是否找不到行。 (通常只检查PK,所以我不知道您是否也在检查其他内容。)
另一个优化...有时建立“覆盖”索引很有用。这是一个INDEX
,其中包含{em> all (对于一个表)在SELECT
中 anywhere 中提到的列。这似乎不切实际,因为在这4种情况下,每种情况都会涉及很多列。
答案 2 :(得分:0)
基本上,您想从where
子句中的可索引列开始。您没有任何内容(由于函数调用)。因此,然后从join
列开始:
from tblselection a join
table1 c
on c.col1 = a.col1 join
table2 d
on d.Id = a.table2Id left join
tabletest
on b.SelectionId = a.selectionId and a.table2Id = b.table2Id and b.IsMatched = 1
我将从table1(col1)
,table2(id)
和tabletest(SelectionId, table2Id, IsMatched)
开始。