如何确定最适合索引的列

时间:2018-06-26 19:23:03

标签: mysql sql indexing

我已经阅读了很多有关识别列的主题,这些列可能是创建索引的最佳人选。但是,大多数建议在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个表中,哪个列是索引的最佳选择?

我应该在这里创建复合索引还是单个索引?

3 个答案:

答案 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 TABLEEXPLAIN SELECT...

您现在可能会看到cEXPLAIN中的第一张表。让我们通过提供

来帮助优化器
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引用了cb。但是bLEFT JOIN,因此我们不能使用它。剩下c。要索引的唯一有用的列是active(在重新格式化之后)。但这听起来像是Optimizer避开的简单,低基数的“标志”。我在索引中添加了一些内容,希望优化程序会被欺骗使用它。

那么,“下一个”表将是什么? JOINs仅从ca。接下来是aJOIN使用col1

下一步可以是db。看起来,`优化器可以按任意顺序执行它们,并且无论顺序如何,都可以对事物进行相同的优化。

dId是如何到达它。

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)开始。