MySQL에서 NULL 값을 가진 열의 인덱스를 디자인하는 방법은 무엇입니까?


11

4 천만 개의 항목이있는 데이터베이스가 있고 다음 WHERE절을 사용하여 쿼리를 실행하려고합니다.

...
WHERE
  `POP1` IS NOT NULL 
  && `VT`='ABC'
  && (`SOURCE`='HOME')
  && (`alt` RLIKE '^[AaCcGgTt]$')
  && (`ref` RLIKE '^[AaCcGgTt]$')
  && (`AA` RLIKE '^[AaCcGgTt]$')
  && (`ref` = `AA` || `alt` = `AA`)
LIMIT 10 ;

POP1NULL 일 수도있는 float 열입니다. POP1 IS NOT NULL항목의 약 50 %를 제외해야하므로 처음에 입력해야합니다. 다른 모든 용어는 숫자를 조금만 줄입니다.

무엇보다도, 나는 인덱스를 디자인 pop1_vt_source했는데, 이것은 사용되지 않는 것 같지만 vt첫 번째 열이 있는 인덱스 가 사용되었습니다. 설명 출력 :

| id | select_type | table | type | possible_keys                          | key                 | key_len | ref         | rows     | Extra       |
|  1 | SIMPLE      | myTab | ref  | vt_source_pop1_pop2,pop1_vt_source,... | vt_source_pop1_pop2 | 206     | const,const | 20040021 | Using where |

pop1첫 번째 열 이있는 인덱스가 사용되지 않는 이유는 무엇 입니까? 때문에 NOT또는 NULL일반적으로. 색인 및 WHERE 절의 디자인을 개선하려면 어떻게해야합니까? 10 개 항목으로 제한하더라도 테이블의 처음 100 개 항목에 10 개의 일치 항목이 포함되어 있지만 쿼리에 30 초 이상이 걸립니다.

답변:


10

그것은이다 NOT NULL:

CREATE TEMPORARY TABLE `myTab` (`notnul` FLOAT, `nul` FLOAT);
INSERT INTO `myTab` VALUES (1, NULL), (1, 2), (1, NULL), (1, 2), (1, NULL), (1, 2), (1, NULL), (1, 2), (1, NULL), (1, 2), (1, NULL), (1, 2);
SELECT * FROM `myTab`;

제공합니다 :

+--------+------+
| notnul | nul  |
+--------+------+
|      1 | NULL |
|      1 |    2 |
|      1 | NULL |
|      1 |    2 |
|      1 | NULL |
|      1 |    2 |
|      1 | NULL |
|      1 |    2 |
|      1 | NULL |
|      1 |    2 |
|      1 | NULL |
|      1 |    2 |
+--------+------+

색인을 작성하십시오.

CREATE INDEX `notnul_nul` ON `myTab` (`notnul`, `nul`);
CREATE INDEX `nul_notnul` ON `myTab` (`nul`, `notnul`);

SHOW INDEX FROM `myTab`;

제공합니다 :

+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| myTab |          1 | notnul_nul |            1 | notnul      | A         |          12 |     NULL | NULL   | YES  | BTREE      |         |               |
| myTab |          1 | notnul_nul |            2 | nul         | A         |          12 |     NULL | NULL   | YES  | BTREE      |         |               |
| myTab |          1 | nul_notnul |            1 | nul         | A         |          12 |     NULL | NULL   | YES  | BTREE      |         |               |
| myTab |          1 | nul_notnul |            2 | notnul      | A         |          12 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

이제 선택을 설명하십시오. MySQL을 사용하더라도 색인을 사용하는 것 같습니다 NOT NULL.

EXPLAIN SELECT * FROM `myTab` WHERE `notnul` IS NOT NULL;
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+ 
| id | select_type | table | type  | possible_keys | key        | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+ 
|  1 | SIMPLE      | myTab | index | notnul_nul    | notnul_nul | 10      | NULL |   12 | Using where; Using index |
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+


EXPLAIN SELECT * FROM `myTab` WHERE `nul` IS NOT NULL;
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys | key        | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | myTab | range | nul_notnul    | nul_notnul | 5       | NULL |    6 | Using where; Using index |
+----+-------------+-------+-------+---------------+------------+---------+------+------+--------------------------+

비교 때, NOT NULL그리고 NULL, 그것을 사용하는 경우 MySQL이 다른 인덱스를 preferrs 것으로 보인다 NOT NULL. 이것은 분명히 정보를 추가하지는 않습니다. 이것은 MySQL이 NOT NULL타입 열에서 볼 수있는 범위로 해석하기 때문 입니다. 해결 방법이 있는지 확실하지 않습니다.

EXPLAIN SELECT * FROM `myTab` WHERE `nul` IS NULL && notnul=2;
+----+-------------+-------+------+-----------------------+------------+---------+-------------+------+--------------------------+
| id | select_type | table | type | possible_keys         | key        | key_len | ref         | rows | Extra                    |
+----+-------------+-------+------+-----------------------+------------+---------+-------------+------+--------------------------+
|  1 | SIMPLE      | myTab | ref  | notnul_nul,nul_notnul | notnul_nul | 10      | const,const |    1 | Using where; Using index |
+----+-------------+-------+------+-----------------------+------------+---------+-------------+------+--------------------------+


EXPLAIN SELECT * FROM `myTab` WHERE `nul` IS NOT NULL && notnul=2;
+----+-------------+-------+-------+-----------------------+------------+---------+------+------+--------------------------+
| id | select_type | table | type  | possible_keys         | key        | key_len | ref  | rows | Extra                    |
+----+-------------+-------+-------+-----------------------+------------+---------+------+------+--------------------------+
|  1 | SIMPLE      | myTab | range | notnul_nul,nul_notnul | notnul_nul | 10      | NULL |    1 | Using where; Using index |
+----+-------------+-------+-------+-----------------------+------------+---------+------+------+--------------------------+

나는 NULL특별한 가치 이기 때문에 MySQL에서 더 나은 구현이있을 수 있다고 생각 합니다. 아마도 대부분의 사람들은 NOT NULL가치에 관심이 있습니다.


3

문제는 NULL 값이 아닙니다. 인덱스의 선택성입니다. 귀하의 예에서 source, pop1의 선택성은 just의 선택성보다 낫습니다 pop1. 이 where절의 더 많은 조건을 다루므로 페이지 적중을 줄일 가능성이 높습니다.

행 수를 50 % 줄이는 것으로 충분하다고 생각할 수도 있지만 실제로는 충분하지 않습니다. where절 에서 색인의 장점은 읽는 페이지 수를 줄이는 것입니다. 페이지에 NULL이 아닌 값을 가진 레코드가 평균적으로 하나 이상 있으면 인덱스를 사용할 수 없습니다. 페이지 당 10 개의 레코드가 있으면 거의 모든 페이지에 해당 레코드 중 하나가 있습니다.

에 색인을 시도 할 수 있습니다 (pop1, vt, source). 옵티마이 저가이를 선택해야합니다.

그러나 결국 where조항이 기록을 잃어 버린 경우 규칙이 없지만 20 %라고 말하면 색인이 도움이되지 않을 것입니다. 인덱스 에 쿼리에 필요한 모든 열이 포함 된 경우는 예외입니다 . 그런 다음 각 레코드의 데이터 페이지를 가져 오지 않고 쿼리를 만족시킬 수 있습니다.

그리고 인덱스를 사용하고 선택성이 높으면 인덱스가없는 성능보다 인덱스의 성능이 떨어질 수 있습니다.


나는 그것이 실제로 차이를 일으키는 범위라고 생각합니다 (내 대답 참조). 대부분의 사람들이 NOT NULL열에 관심이 있기 때문에 MySQL에서 더 잘 구현 될 수 있다고 생각합니다 .
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.