InnoDBの詳細かつB +ツリーインデックス

インデックスとは何ですか

具体的な情報インデックスデータベースのテーブルにランク付け、高速アクセスを構成するためのデータベーステーブル内のインデックスまたは列の値です。

たとえば、私たちは辞書小学校のテキスト検索を使用する場合、見つける、この時間はインデックスディレクトリに合わせて有効になっているカタログ。内容のないテーブルが存在しない場合、我々は文字を検索したい場合は、最初のオーダーを開始してから横断することができます。したがって、インデックスは、検索速度を向上させるためのツールです。

InnoDB内のインデックス構造

リコールB +ツリー

データベースのインデックスを説明する前にのはなぜ何、それを確認する必要があり、B +ツリーを見てみましょうか?InnoDBは、インデックスの形で実現するので達成するB +ツリーです。

B +ツリーに関連概念の学生がデータを確認することができます。ここでは、データベースのインデックス構造として使用するのに適した彼のいくつかの機能のいくつかを見て

  1. K番目のノードツリーのは、(BツリーはK-1の要素である)、データの各要素が保存されていない中間要素をk個が含まれ、唯一使用されるインデックス、リーフノードに格納されたすべてのデータ。中間ノードがデータを保存しないので、データはこのようにより、より大きなインデックス、有効ディスクアクセスIOを減らすことができ、より多くの情報を得るために、単一のディスクアクセスのために同じ空間に格納されています。各ルックアップ性能が非常に安定しているので、データのみので、リーフノードに格納されています。
  2. すべてのリーフノードのすべての要素の情報が含まれており、これらの要素は、サイズと順次リンクもたらした大きなキーワードに応じて、レコードへのポインタ、およびリーフノード自体を含んでいます。MySQLはリレーショナルデータベースは、アクセス間隔は一般的なシナリオであり、子ノードを効果的に一緒に文字列が関係リストのサイズに基づいて、アクセス部の効率を向上させることができます。

私たちは、検索処理B +ツリーに慣れるためにマップを見てください。

その後、次のようにプロセスが見つけ、我々は数4を見つけたいとします。

最初のディスクアクセス

第2のディスクアクセス

第三ディスクアクセス

最も基本的なインデックス - 主キー索引

単独でリンクされたリスト内のデータベース・データページ内のデータは、マスターキーに基づいて形成されています。各データ・ページは、一緒に文字列にデータ・ページがいっぱいになった場合、我々はデータを格納するために複数のデータページを必要とするので、一定のサイズを有し、データ・ページリストを。上限は、現在格納できるデータのページのデータが2であると仮定されます。だから我々は、データがどのように見えるかもしれませんデータベースに格納されているものを推測する必要があります。

しかし、我々は我々が必要とするデータを見つけることがポイントに上記の構造のリストに従って、グローバルスキャンヘッドスタートの保存だけに見えます。

あなたは、クエリの効率を向上させることができるならば、我々はB +ツリーで構成インデックスデータ構造の部分を増やすのだろうか?答えはイエス間違いです。その後、我々は、下の図に変換します。

学生は二つのデータページは、それが保存されている尋ねありませんか?どのように数字いくつかの3?このため、これはB +ツリーです無視してください、中間ノードは、データポイントを保存することがあります。(根本的な問題は、元のマップを再利用し、私は怠け者だということです)

主キーは、テーブルの通常のデータ・ページ内のデータテーブルである場合、リーフノード上のデータがページ内の特定の値の大きさに応じて配置され、この値は、テーブルの構築我々のデータベースの主キークラスタ化インデックスは、通常昇順にクラスタ化インデックスをに従って。

私たちは8つのデータの値を挿入した場合、我々はそれについて考える今回は、の構造を変更する方法でしょうか?

私たちは、子ノードの正常性を確保するためには、それだけでページ分割操作することができ、フルである最初の8の位置が格納されるべき見つけると、このページが持っていました。このような効率が大幅に低下します。だから我々は常にプライマリキーとしてデフォルトの増分配列データベースを使用するために使用されます。必ずしも必要ではないが、主キーインデックスは、クラスタ化インデックスです。(それを考慮する学生にそのままにしておき)

一般的な指標

シングルフィールドインデックスは、名前から判断し、フィールドにインデックスのみです。インデックスとして共同指数は、聖歌を持つ複数のフィールドです。私たちは、次の表の構造を見て

CREATE TABLE `tb_predict_user_info` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键id,赛季id',
  `user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '用户ID',
  `app_id` int(11) NOT NULL DEFAULT '0' COMMENT '用户的appID',
  `bonus_amount` bigint(20) NOT NULL DEFAULT '0' COMMENT '用户红包的总金额,单位分',
  `is_del` tinyint(4) NOT NULL DEFAULT '0' COMMENT '软删除标记,0:未删除1:已删除',
  `create_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '记录创建时间',
  `update_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '记录最后更新时间',
  PRIMARY KEY (`id`),
  KEY `index_user` (`user_id`)
  KEY `index_user_app` (`app_id`,`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';
复制代码
  • index_userは、単一フィールドインデックスであります
  • index_user_appは共同指標であります

上記の表では、データベース構造に保存されているが何もありか?

各インデックス内では、InnoDBはB +ツリーデータインデックスを作成しますが、データの整合性、他のB +ツリーのリーフノードを保持しますスペース上の理由から、唯一のクラスタ化インデックスのリーフ・ノードを節約するために、のみ対応するインデックスを保存しますデータフィールド。

データベース形式の行に以下に示すように簡略化することができます

RECORD_TYPE:データの種類

  • 0:通常のユーザレコード
  • 1:ディレクトリレコード
  • 2:最小レコード
  • 3:最大レコード

以下のようにインデックスページ

データページ次図

InnoDBのインデックスは、クエリで使用されます

私たちの上に、データがデータベースに保存されたB +ツリーデータである方法を述べました。だから、どのように我々は何のデータを見つけるために時間を見つけるのですか?

主キーのインデックスで検索プロセスは、単にその次の手順として理解することができないのですか?

  1. 主キーのデータ10000を想定して下さい。
  2. 同じページのデータがすでにソートされているので、半分のページで見つけることができます。
  3. どこインデックス半分に次のレベルのルート・ページを見つけるために見つけます。
  4. そして、そのリーフノードを見つけます。
  5. リーフノードで対象データが存在して下さい。

上面我们说了在Innodb中有多少个索引就有多少个B+树,那么这样的话数据会不会重复?如何解决这个问题哪?

答案当然是不会重复啊!只有主键索引(聚簇索引)的叶子节点才会保存所有的数据,而其他的索引中并不会保存所有的数据,只保存了作为索引的值以及该条记录所在的主键值。

那么我们根据普通索引的过程又是如何哪?

其实跟我们通过主键索引查找很类似,只是由于叶子节点不保存记录的所有数据,所以需要根据主键再次进行一次查找,这个过程就是我们通常说的回表(回表:再次回到表中进行一次查询)。

既然又回表,那么如何避免回表哪?

叶子节点不保存记录的所有字段,但是保存了索引字段的值啊,那么如果我们查询的字段只有索引字段,是不是就可以避免回表了哪?

答对了,如果我们的查询字段的所有字段都可以被使用到的索引字段所覆盖,那么就可以避免回表,这就是我们通常说的覆盖索引。

范围查询走索引么?

上面我们说的都是指定某个索引条件进行查询,但是在日常开发中我们不可避免的会遇到范围查询(>,<,!=)等等,网上查找相关资料,有人说不走索引,有人说走索引(网络是开放的,大家需要自行识别真伪),那么范围查询到底走不走索引?如果走索引,这个时候索引在我们的查询中又有什么作用哪?

我们还是回到B+树的查找过程。 大家先自己想一下,如果你在B+树中查找 索引值>5000某个值时会如何操作哪?

  1. 由于在数据库的B+树中,数据都是从大到小进行排列。
  2. 我们先查找id=5000的值所在的叶子节点,然后通过next指针顺序遍历查找符合条件的值
  3. 通过回表进行其他字段的查找。

上面的过程就是在>,<的情况下如如何走索引的 注:由于数据库查询引擎的自动优化,同学在测试这个场景的时候最好加上limit来限定查询个数,如果查询个数过多可能会触发全表扫描。

还有一种类似于!=的操作,那么这个走索引么? 我们大家来思考一下,通过B+树来查找一个!=某个值的数据要如何操作哪? 1、先找到等于这个值的数据,然后查找其他的数据?

是不是感觉跟全表扫描差不多(全表扫描还不需要回表哪!),我们可以认为这样操作的效率要低于全表扫描,没表要使用到索引啊,所以这类查询并不会用到索引。

索引除了在where条件中会用到,在order by的字段中会用到么?

还是之前的方式,我们来思考一下,如果我们的查询是 select * from tb_table order by id asc limit 100。这个时候要如何查询哪? 1、由于表中的数据都是按照id进行从大到小排序的。 2、所以我们只要找到id最小的,然后顺序遍历出符合条件个数的值。 3、如果需要回表在进行回表操作

order by一定会走索引么?

order by原来也会用到索引啊!那么如果我们的索引是userid_tradeDay,查询条件是 select * from table order by userid desc, tradeDay asc,两个排序条件不一致。这个时候还会走索引么? 老方式,再来看一下这个查询我们在B+树中应该如何操作。

B+树中的索引字段都是按照从小到大排列的,我们要查询这两个索引的排序方式不一致,,,,,,,,,,,无法用到索引啊。

在来看一种情况

如果我们的索引是userid_tradeDay,查询条件是 select * from table where user_id = ?, userid和tradeDay作为联合索引,但是查询条件中的where条件只有user_id, 第二个查询条件是 select * from table where trade_day = ?,查询条件只有trade_day,没有user_id。

上面两个查询会走索引么? 还是从B+树出发。 1、我们的索引是先按照user_id从小到大排序,在按照trade_day从小到大排序。 2、我们的查询条件是user_id,那么当作trade_day没有呗,这样不就走索引进行查询了么。 3、我们的查询条件是trade_day,先按照。。。。。。啊啊啊啊啊啊啊,走不了索引我,我想不出啊啊啊啊啊啊啊啊啊啊。

上面所说的就是左前缀匹配原则,那么我们的where条件中使用了user_id和trade_day,但是两个顺序在where条件中颠倒了会走索引么。 会的,查询优化器会帮我们做的。

我们来看下面的表

CREATE TABLE `tb_user_info` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键id,赛季id',
  `user_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '用户ID',
  `user_id_c` varchar(200) NOT NULL DEFAULT '' COMMENT '用户ID',
  PRIMARY KEY (`id`),
  KEY `index_user` (`user_id`)
  KEY `index_userc` (`user_id_c`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';
复制代码

上面的表主要有两列int类型的user_id和varchar类型的user_id_c以及相关索引。 我们表中存在一下数据

带引号是为了说明是字符串 我们看下面几个查询语句。 A:select * from tb_user_info where user_id = 0; B:select * from tb_user_info where user_id = '0'; C:select * from tb_user_info where user_id = 'abc'; D:select * from tb_user_info where user_id_c = 0; E:select * from tb_user_info where user_id_c = '0'; F:select * from tb_user_info where user_id_c = 'abc'; 上面6条语句的查询结果是什么,以及上面查询是否走索引了哪? A:查询结果为id=1的数据,走了index_user索引。

B:查询结果为id=1的数据,走了index_user索引。

C:查询结果为id=1的数据,走了index_user索引。

D:查询结果为id=1的数据,走了index_user_c索引

E:查询结果为id=1的数据,走了index_user_c索引

F:查询结果为空,走了index_user_c索引

看到这里是不是有疑问? 1、我都建立索引了,怎么有时候走,有时候不走? 2、我查=’abc‘的怎么返回了=0的数据?

这里我们引入了一个概念:隐式转换

在我们查询条件的类型和数据库字段的类型不一致时,mysql会进行会进行以下操作:

  1. 两个参数至少有一个是 NULL 时,比较的结果也是 NULL,例外是使用 ⇔ 对1. 两个 NULL 做比较时会返回 1,这两种情况都不需要做类型转换 两个参数都是字符串,会按照字符串来比较,不做类型转换
  2. 两个参数都是整数,按照整数来比较,不做类型转换
  3. 十六进制的值和非数字做比较时,会被当做二进制串
    1. 有一个参数是 TIMESTAMP 或 DATETIME,并且另外一个参数是常量,常量会被转换为 timestamp 有一个参数是 decimal 类型,如果另外一个参数是 decimal 或者整数,会将整数转换为 decimal 后进行比较,如果另外一个参数是浮点数,则会把 decimal 转换为浮点数进行比较
  4. 所有其他情况下,两个参数都会被转换为浮点数再进行比较

针对上面的原则我们来看刚才我们的疑问

1、我都建立索引了,怎么有时候走,有时候不走? 发现了没,走索引的都是类型一致或者数据库类型是int类型的? 类型一致走索引没有什么疑问,那为什么类型转换后有可能不走索引哪? 我们来想以下float数字的排序和字母的排序: 3,21 '21','3', 类型不一致时排序结果不一样啊同学!。 所以按照我的理解,可以简单认为发生隐式类型转换的时候,如果转换方是数据库的字段类型,这个时候索引就不生效了。(也不知道对不对,欢迎同学Diss) 2、我查=’abc‘的怎么返回了=0的数据? 类型不一致会进行转换啊!‘abc’转换的时候转为为数字是多少哪?无法转换啊,当然就是默认的0了,所以~你懂的。

总结:

当不知道走不走索引的时候,就会想一下B+树,如果查询条件是xxx,索引是xxx,我来查询的时候如何能够最优。。。。。。

おすすめ

転載: juejin.im/post/5df64970f265da339d106059