blog

MysqlのIS NULLは、IS NOT NULLはインデックスに行くことができない?

私は理由が何であるかを知りませんし、いつ、ジャングルの中で、mysqlのクエリ条件がIS NULL、IS NOT NULL、!=、%*のように、%*%のように、インデックスクエリを使用することはできま...

Mar 8, 2020 · 4 min. read
Share this

私は理由が何であるかを知りませんまた、ジャングルのことわざは、mysqlのクエリの条件がIS NULL、IS NOT NULL、!=、%*のように、%*%のようにインデックスクエリを使用することはできません唯一のフルテーブルスキャンを使用することができます。

私もこの業界に入った当初は同じことを考え、それを真実だと信じていました!

しかし、あなたはまだああインデックスに行く見つける時間の仕事!ここでは、謎を一つずつ見てみましょう。

まず、最初の検証がインデックスされます。

次のような構造のテーブルを作成します:

 create table user_info( 
 
 id int PRIMARY key auto_increment, 
 
 name varchar(16) default '', 
 
 age tinyint default 0, 
 
 address varchar(32) default '', 
 
 PRIMARY KEY (`id`), 
 
 KEY `name` (`name`), 
 
 KEY `address_2` (`address`,`name`) 
 
 ); 
 
 ALTER TABLE user_info ADD INDEX (NAME); 
 
 ALTER TABLE user_info ADD INDEX (address);
 データ1
 
 INSERT INTO user_info(NAME,age,address) 
 
 VALUES (9,9,'shenzhen9'); 
 
 BEGIN 
 
 DECLARE i INT DEFAULT 1000; 
 
 WHILE i < 9000 DO 
 
 INSERT INTO user_info (`NAME`, `age`, `address`) 
 
 VALUES 
 
 (NULL, i , SUBSTRING(MD5(RAND()),1,10) ) ; 
 
 SET i = i+ 1 ; 
 
 END WHILE ; 1.  EXPLAIN SELECT * FROM user_info WHERE `name` IS NOT NULL 2.  EXPLAIN SELECT * FROM user_info WHERE `name` !='9' 3.  EXPLAIN SELECT * FROM user_info WHERE `name` is null
 データ2
 
 INSERT INTO user_info(NAME,age,address) 
 
 VALUES (null,9,'shenzhen9'); 
 
 BEGIN 
 
 DECLARE i INT DEFAULT 1000; 
 
 WHILE i < 9000 DO 
 
 INSERT INTO user_info (`NAME`, `age`, `address`) 
 
 VALUES 
 
 (REPLACE(UUID(),'-',''), i , SUBSTRING(MD5(RAND()),1,10) ) ; 
 
 SET i = i+ 1 ; 
 
 END WHILE ; 
 
 選択について説明する* FROM user_info WHERE `name` IS NOT NULL 
 
 選択について説明する* FROM user_info WHERE `name` !='9' 
 
 セレクトを説明する* FROM user_info WHERE `name` is null

データ1を実行すると、sql ①②はインデックスへ、③はインデックスへ行かないことがわかります。

data2を実行すると、sql⑥はインデックスに移動し、④⑤は移動しません。

II. B+ツリーのデータ配置ルール

1. クラスタ化インデックスインデックス:

ページ内のレコードは主キーの値でソートされます;

B+ツリーの各レベルのノードは、ページ内のレコードの主キー値のサイズに従ってソートされます;

(iii) 完全なユーザーレコードは、B+木の葉ノードに対応するページに格納されます;

2.二次インデックス

ページ内のレコードは、指定されたインデックス・カラムの値でソートされます。

B+木の各レベルのノードは、ページに記録されている所定のインデックス列の値に従ってソートされます。

(iii) B+ツリーのリーフノードに対応するページに格納されるのは、インデックス列の値+主キーの値だけです。

セカンダリインデックス値はNULLである可能性があります。では、インデックス列の値が NULL であるセカンダリ インデックス レコードは、B+ ツリーのどこにあるのでしょうか。

B+ツリーの左端にあります。以下に示すように

なぜかというと、InnoDBはSQLのNULL値はカラムの最小値であると述べています。

インデックスが機能しなくなったのはいつからですか?

ヌル値の数のデータ1とデータ2の2つのデータの比較は、ヌル値の大半はヌルではないとされている場合、同じではありません!=インデックスに移動し、ヌルはインデックスに移動しませんが、データ2はその逆です。

と推定されます。nullを使用してインデックス化されたフィールドでは、問題のコストに煮詰められたデータ量でインデックスに移動するかどうかを決定します。

インデックスのスキャン費用

1.索引記録の読み取りコスト

2、逆プライマリキーインデックスは、テーブルに戻る完全なデータコストを見つけるために

クエリは、より多くのセカンダリインデックスを読み取る場合は、特定の割合まで、すべてのクエリになりますより多くの回をクエリするテーブルに戻る必要がある、つまり、上記のNULLクエリインデックスは、時には理由を効果を取ることはありません。

要約すると、MySQL でクエリを実行する際に特定のインデックスを使用しないかどうかは、コストの大きさに基づいて決定されます。IS NULL, IS NOT NULL, != これらの条件を使用する代わりに

第三に、'% 文字列 %', '文字列 %' のようなインデックスを作成する方法です。

通常、%*%のように使用して、%*は、インデックスに移動しませんが、それはインデックスに移動することはできませんという意味ではありません、名前と年齢上記のテーブルの複合インデックスを確立するために

 explain select name from user_info where name like '%a%'; 
 
 1 SIMPLE user_info index idx_n_a  Using where; Using index 
 
 explain select name,age from user_info where name like '%a%'; 
 
 1 SIMPLE user_info index idx_n_a  Using where; Using index 
 
 次の2つの例では、クエリが列の複合インデックスにされていないため、フルテーブルスキャンを引き起こす。
 
 explain select name,age,address from user_info where name like '%a%'; 
 
 1 SIMPLE user_info ALL 6 16.67 Using where 
 
 explain select * from user_info where name like '%a%'; 
 
 1 SIMPLE user_info ALL 6 16.67 Using where

だから、インデックスに載るか載らないかは、絶対的なものではなく、使用状況によって変わります!

Read next

ズーキーパー

1.関連コマンド

Mar 7, 2020 · 2 min read