MySQL InnoDB复合索引的性能和基数

我想问几个有关InnoDB引擎的复合索引中的列顺序以及有关在提供的示例中获得最佳性能所必须满足的基数和选择性说明(以及如何做到这一点)的问题

  1. 在InnoDb复合索引性能的背景下,选择性和基数有什么区别?
  2. 如果创建复合索引,什么时候应该强调选择性,什么时候要强调基数?

由于InnoDB使用B-Tree(B-Tree +)索引,并且从创建索引的最左列开始搜索复合索引。

我的理解是,使用这样的列组合顺序是有道理的,即最左边的列将把索引中最大的不匹配部分丢出搜索,并继续以更少的数据进行搜索, 复合索引的下一列应具有相同的属性,因此所有其他列,直到搜索缩小行数 可能匹配到它可以扫描以查找完全匹配的行的最小数量。

简而言之,据我了解,最左边的列应该是所有行中最粗粒度的划分,而复合索引的下一列应该越来越细。

  1. 这是基数吗?如果综合索引是按照我所描述的那样构建的,那么基数是高还是低?

  2. 选择性如何?这与基数有关吗?

5。如何为下表设计获得最佳的选择性和基数?

CREATE TABLE IF NOT EXISTS `data_list` (
  `one` varchar(64) NOT NULL,`two` mediumint unsigned NOT NULL,`three` varchar(128) NOT NULL,`four` datetime NOT NULL,`five` DECIMAL(5,2)
) ENGINE = InnoDB;

列的最大不重复计数值为:
one最多10;
two最多100;
three最多1000;
four最高36500; // 100年

用于临时联接的第二张表:

CREATE TEMPORARY TABLE IF NOT EXISTS `three_list` (
    `l_three` varchar(128) PRIMARY KEY NOT NULL
) ENGINE = InnoDB;

将要发出的查询:

(A)查询特定的onetwothreefour

SELECT *
FROM 
    `data_list`
WHERE 
    `one` = 'abc'
AND    
    `two` = 1
AND    
    `three` = 'xyz'
AND    
    `four` = '2018-01-01'
;

(B)查询特定的onetwothree和范围four

SELECT *
FROM 
    `data_list`
WHERE 
    `one` = 'abc'
AND    
    `two` = 1
AND    
    `three` = 'xyz'
AND    
    `four` >= '2018-01-01'
AND
    `four` < '2019-01-01'
ORDER BY
    `two`,`three`,`four`
;

(C)查询特定的onetwothree范围内的任何four

SELECT *
FROM 
    `data_list`
WHERE 
    `one` = 'abc'
AND    
    `two` = 1
AND    
    `four` >= '2018-01-01'
AND
    `four` < '2019-01-01'
ORDER BY
    `two`,`four`
;

(D)用JOIN查询特定的onetwothree在范围内的列表three_listfour

SELECT *
FROM 
    `data_list`
INNER JOIN 
    `three_list`
ON 
    `three` = `l_three`
WHERE 
    `one` = 'abc'
AND    
    `two` = 1
AND    
    `four` >= '2018-01-01'
AND
    `four` < '2019-01-01'
ORDER BY
    `two`,`four`
;

也许整个表设计从一开始就存在缺陷(即由于没有id的PK data_list和auto_increment)。这个问题是关于综合索引的最佳性能的基数和选择性,但是,如果上面没有用于查询的好的列顺序选择,那么也欢迎使用替代表设计。

对我来说,最重要的性能是SELECT语句。 INSERT将很少见(每天一次),并且不需要UPDATE,DELETE。

行在data_list中必须是唯一的,我的意思是onetwothreefour列值的组合。

book1841 回答:MySQL InnoDB复合索引的性能和基数

单个列的基数和选择性 复合索引无关。

将InnoDB BTree索引中的值视为指定列的串联。

以大致此顺序的列填充索引:

  1. 使用“ =”测试的列,即使它是“标志”。
  2. IN(const,...)-优化器可能可以跳过索引。
  3. 一个“范围”。没有更多的范围。

“覆盖”索引会导致某些异常。

您的示例:

(A)查询特定的一,二,三,四:

    INDEX(one,two,three,four) -- in _any_ order

(B)查询特定的一,二,三和四的范围

    INDEX(one,-- put these first (=),in _any_ order
          four)             -- after the =s

ORDER BY也将被处理

(C)查询四个范围内的特定一个,两个和任意三个

    INDEX(one,-- either order; including `three` would hurt
          four)             -- after the =s

但是,这次ORDER BY two,four也无法处理;将会有一个“文件排序”。

或者(虽然不太可能),优化器可能选择使用ORDER BY而不是WHERE。在这种情况下,这是最佳选择:

INDEX(two,four)  -- in the same order as the ORDER BY.

(D)使用JOIN查询特定的一和二,三个在列表three_list中,四个在范围内

这变得棘手,因为优化器将选择从哪个表开始。 通常会选择一个具有更多可用过滤功能的设备,您是要对data_list中的一,二,四进行过滤吗?但是在另一张桌子上根本没有。所以...

data_list: INDEX(one,-- either order,four)       -- range
three_list;  INDEX(l_three)

更多:http://mysql.rjweb.org/doc.php/index_cookbook_mysql

“没有PK”-是的,这很糟糕。但这不必是AUTO_INCREMENT;如果您没有从一个(或多个)列构建的“自然” PK,这是一个后备。

AUTO_INCREMENT不会将列强制为PK。但是,您必须在AUTO_INCREMENT列中添加 some 索引 starting 。那是唯一的约束。

“还欢迎使用其他表格设计”-我们需要对one(等等)的真实含义有所了解。

如果您有这4个查询,并且想要最佳的索引集:

INDEX(one,four)
INDEX(one,four)
INDEX(     two,four)

(其他连击效果也一样。)

如果您在SELECT子句中更具选择性,那么我还将讨论“覆盖”索引。

本文链接:https://www.f2er.com/3134558.html

大家都在问