MySql의 VARCHAR 필드에 가능한 INDEX


40

나는 MySql 데이터베이스 에서 다음과 같은 테이블로 작업하고 있습니다 .

+--------------+
|  table_name  |
+--------------+
|    myField   |
+--------------+

... 그리고 목록에 5-10 개의 문자열 이있는 많은 쿼리를 작성해야합니다 .

SELECT myField FROM table_name
WHERE myField IN ('something', 'other stuff', 'some other a bit longer'...)

약 24.000.000 개의 고유 한 행이 있습니다.

1) 나는 사용해야 FULLTEXT나하고 INDEX내 키입니다 VARCHAR(150)?
2) 문자를 150에서 220 또는 250으로 늘리면 큰 차이가 있습니까? (계산할 방법이 있습니까?)
3) 내가 말했듯이, 고유 할 것이므로 myFieldPRIMARY KEY 이어야합니다 . 이미 VARCHAR INDEX / FULLTEXT 인 필드에 PRIMARY KEY를 추가하는 것은 드문 일이 아닙니까?


고유성을 위해 PRIMARY를 사용할 필요는 없습니다. 이미 고유 한 것이 있습니다.
kommradHomer

답변:


62

제안 # 1 : 표준 색인

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    key (myfield)
);

이런 식으로 색인을 작성하면 전체 문자열을 찾거나 왼쪽 방향의 LIKE 검색을 수행 할 수 있습니다

제안 # 2 : 전체 텍스트 인덱싱

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    primary key (id),
    fulltext (myfield)
);

전체 구문뿐만 아니라 개별 키워드에 대한 검색을 효과적으로 사용할 수 있습니다. MySQL은 543 단어의 색인을 생성하지 않기 때문에 커스텀 스톱 워드 목록을 정의해야합니다 .

다음은 FULLTEXT 지수에 대한 지난 2 년간의 다른 게시물입니다.

제안 # 3 : 해시 인덱싱

CREATE TABLE mytable
(
    id int not null auto_increment,
    myfield varchar(255) not null,
    hashmyfield char(32) not null,
    primary key (id),
    key (hashmyfield)
);

하나의 특정 값을 찾고 해당 값의 길이가 32자를 넘으면 해시 값을 저장할 수 있습니다.

INSERT INTO mytable (myfield,hashmyfield)
VALUES ('whatever',MD5('whatever'));

그렇게하면 해시 값을 검색하여 결과를 검색 할 수 있습니다

SELECT * FROM mytable WHERE hashmyfield = MD5('whatever');

시도 해봐 !!!


귀하의 답변에 투표 할만큼 평판이 좋지 않지만 그 답변이 훌륭하다고 말해야합니다. 설명과 예제에 감사드립니다. 해시 인덱싱이 내 경우에 가장 적합하다고 생각합니다. 굉장한 솔루션입니다. 그러나 여전히 하나의 질문 : 당신은 테이블에서 빠른 검색을위한 행의 한계가 어떻게 될 것이라고 생각합니까? [검색을 위해 VARCHAR (32)를 KEY로 사용]
Mark Tower

2
여기서 해시 옵션은 여전히 ​​16 바이트 텍스트에 대한 텍스트와 32 바이트입니다. conv (left (md5 ( 'whatever'), 16), 16, -10)와 함께 bigint 필드를 사용할 수 있습니다. 이 16 바이트 숫자는 아니지만 당신은 MD5의 절반 충분한을 찾을 수 있으며, 다음은 인덱스 만 8 바이트의
atxdba

1
색인화 될 문자열을 생성하기 위해 MD5 또는 SHA1을 사용하는 것은 좋지 않습니다. MD5 또는 SHA1과 같은 해싱 함수로 생성 된 문자열의 분포는 넓은 공간에서 임의적이므로 인덱스의 효율성이 떨어 지므로 INSERT 및 SELECT 문이 느려질 수 있습니다. 여기를 설명하는 게시물 : code-epicenter.com/...
Mr.M

이것이 오래된 스레드이므로 죄송합니다.이 질문과 직접 ​​관련이 있지만 위의 기사 및 기타 유사한 기사를 읽으면 내 요구에 대한 명확한 대답을 얻을 수 없습니다. 내 시나리오는 : 현재 하나의 테이블로 구성된 초보적인 재고 시스템을 개발 중입니다. API를 통해 외부에서 액세스되므로 모든 구성이 다른 곳에 유지되므로 단일 테이블 만 필요한 이유입니다. 인덱싱에 대해 생각하고있는 두 개의 열에는 길이가 20 자 미만인 약 200 개의 고유 한 항목이 각각 있습니다. 인덱스 추가를 고려해야합니까?
Mike

이것은 검색과 같은 왼쪽 방향 like 'a%'입니까?
회계사 م

18

MySQL을 사용하면 접두사 인덱스를 정의 할 수 있습니다. 즉, 색인 할 원본 문자열에서 첫 번째 N 문자를 정의한다는 것을 의미합니다. 비교는 좋은 선택성을 제공 할 수있을만큼 길지만 공간을 절약 할 수있는 짧은 숫자 N을 선택하는 것입니다. 접두사는 전체 열을 인덱싱 할 때와 마찬가지로 인덱스를 거의 유용하게 사용할 수있을 정도로 길어야합니다.

더 나아 가기 전에 몇 가지 중요한 용어를 정의하겠습니다. 인덱스 선택성총 고유 인덱스 값과 총 행 수의 비율입니다 . 테스트 테이블의 예는 다음과 같습니다.

+-----+-----------+
| id  | value     |
+-----+-----------+
| 1   | abc       |
| 2   | abd       |
| 3   | adg       |
+-----+-----------+

첫 문자 (N = 1) 만 인덱싱하면 인덱스 테이블은 다음 테이블과 같습니다.

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| a             | 1,2,3     |
+---------------+-----------+

이 경우 인덱스 선택성은 IS = 1 / 3 = 0.33과 같습니다.

인덱스 문자 수를 2로 늘리면 어떻게 될지 살펴 보자 (N = 2).

+---------------+-----------+
| indexedValue  | rows      |
+---------------+-----------+
| ab             | 1,2      |
| ad             | 3        |
+---------------+-----------+

이 시나리오에서 IS = 2 / 3 = 0.66은 인덱스 선택성을 증가 시켰지만 인덱스 크기도 증가했음을 의미합니다. 속임수는 최소한의 숫자 N을 찾아 최대의 인덱스 선택성을 가져 오는 것 입니다.

데이터베이스 테이블에 대해 계산을 수행 할 수있는 두 가지 방법이 있습니다. 이 데이터베이스 덤프 에 대해 설명하겠습니다 .

테이블 직원의 last_name 열 을 인덱스 에 추가 하고 최상의 인덱스 선택성을 생성하는 가장 작은 숫자 N 을 정의 하려고한다고 가정 해 봅시다 .

먼저 가장 빈번한 성을 식별하겠습니다.

select count(*) as cnt, last_name from employees group by employees.last_name order by cnt

+-----+-------------+
| cnt | last_name   |
+-----+-------------+
| 226 | Baba        |
| 223 | Coorg       |
| 223 | Gelosh      |
| 222 | Farris      |
| 222 | Sudbeck     |
| 221 | Adachi      |
| 220 | Osgood      |
| 218 | Neiman      |
| 218 | Mandell     |
| 218 | Masada      |
| 217 | Boudaillier |
| 217 | Wendorf     |
| 216 | Pettis      |
| 216 | Solares     |
| 216 | Mahnke      |
+-----+-------------+
15 rows in set (0.64 sec)

보시다시피, 성 Baba 가 가장 빈번합니다. 이제 가장 자주 발생하는 last_name 접두사를 5 자리 접두사로 시작합니다.

+-----+--------+
| cnt | prefix |
+-----+--------+
| 794 | Schaa  |
| 758 | Mande  |
| 711 | Schwa  |
| 562 | Angel  |
| 561 | Gecse  |
| 555 | Delgr  |
| 550 | Berna  |
| 547 | Peter  |
| 543 | Cappe  |
| 539 | Stran  |
| 534 | Canna  |
| 485 | Georg  |
| 417 | Neima  |
| 398 | Petti  |
| 398 | Duclo  |
+-----+--------+
15 rows in set (0.55 sec)

모든 접두사에 훨씬 더 많은 발생이 있습니다. 즉, 값이 이전 예제와 거의 같아 질 때까지 N을 늘려야합니다.

다음은 N = 9에 대한 결과입니다

select count(*) as cnt, left(last_name,9) as prefix from employees group by prefix order by cnt desc limit 0,15;

+-----+-----------+
| cnt | prefix    |
+-----+-----------+
| 336 | Schwartzb |
| 226 | Baba      |
| 223 | Coorg     |
| 223 | Gelosh    |
| 222 | Sudbeck   |
| 222 | Farris    |
| 221 | Adachi    |
| 220 | Osgood    |
| 218 | Mandell   |
| 218 | Neiman    |
| 218 | Masada    |
| 217 | Wendorf   |
| 217 | Boudailli |
| 216 | Cummings  |
| 216 | Pettis    |
+-----+-----------+

다음은 N = 10에 대한 결과입니다.

+-----+------------+
| cnt | prefix     |
+-----+------------+
| 226 | Baba       |
| 223 | Coorg      |
| 223 | Gelosh     |
| 222 | Sudbeck    |
| 222 | Farris     |
| 221 | Adachi     |
| 220 | Osgood     |
| 218 | Mandell    |
| 218 | Neiman     |
| 218 | Masada     |
| 217 | Wendorf    |
| 217 | Boudaillie |
| 216 | Cummings   |
| 216 | Pettis     |
| 216 | Solares    |
+-----+------------+
15 rows in set (0.56 sec)

이것은 매우 좋은 결과입니다. 즉, 처음 10 자만 색인으로하여 last_name 열에서 색인을 작성할 수 있습니다 . 테이블 정의 열에서 last_name은로 정의되며 VARCHAR(16)이는 항목 당 6 바이트 (또는성에 UTF8 문자가있는 경우 이상)를 저장 했음을 의미합니다. 이 테이블에는 1637 개의 고유 한 값에 6 바이트를 곱한 값이 약 9KB가 있으며 테이블에 백만 개의 행이 포함되어 있으면이 숫자가 어떻게 증가하는지 상상해보십시오.

MySQL의접두사 색인에서 N 수를 계산하는 다른 방법을 읽을 수 있습니다 .

인덱싱해야하는 값을 생성하기 위해 MD5 및 SHA1 함수를 사용하는 것도 좋은 방법이 아닙니다 . 왜? 게시물을 읽어 MySQL 데이터베이스의 기본 키에 대한 올바른 데이터 유형을 선택하는 방법


이것은 다른 질문에 대한 매우 자세한 답변입니다.
mustaccio

1
농담 해?
Mr.M

무엇이 잘못되었거나 질문에 적용 할 수 없는지 설명 할 수 있습니까?
Mr.M

2
안녕하십니까 나는 실제로 당신의 대답을 좋아합니다. 왜 ? 내 오래된 대답에서 SUGGESTION # 1 :이라고 말했습니다 If you index like this, you can either look for the whole string or do left-oriented LIKE searches. 나는 또한 SUGGESTION # 3에서 말했다 : If you are looking for one specific value and those values could be lengths well beyond 32 characters, you could store the hash value:. 귀하의 답변은 왜 거대한 키를 사용하지 않아야하고 가장 왼쪽 문자를 색인화해야하는지에 대해 적절히 설명하여 성능에 차이를 줄 수 있습니다. 당신의 대답은 여기에 속합니다. 답변을 +1하고 DBA StackExchange에 오신 것을 환영합니다.
RolandoMySQLDBA
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.