- 데이터베이스에서 복합 인덱스를 언제 사용해야합니까?
- 복합 인덱스를 사용하여 성능에 미치는 영향은 무엇입니까?)
- 왜 복합 인덱스를 사용해야합니까?
예를 들어 homes
테이블이 있습니다.
CREATE TABLE IF NOT EXISTS `homes` (
`home_id` int(10) unsigned NOT NULL auto_increment,
`sqft` smallint(5) unsigned NOT NULL,
`year_built` smallint(5) unsigned NOT NULL,
`geolat` decimal(10,6) default NULL,
`geolng` decimal(10,6) default NULL,
PRIMARY KEY (`home_id`),
KEY `geolat` (`geolat`),
KEY `geolng` (`geolng`),
) ENGINE=InnoDB ;
그것은 나를 모두 복합 인덱스를 사용하는 의미가 있는가 geolat
와 geolng
같은 그 :
나는 다음을 바꾼다 :
KEY `geolat` (`geolat`),
KEY `geolng` (`geolng`),
와:
KEY `geolat_geolng` (`geolat`, `geolng`)
그렇다면:
- 왜?
- 복합 인덱스를 사용하여 성능에 미치는 영향은 무엇입니까?)
최신 정보:
많은 사람들이 내가 수행하는 쿼리에 전적으로 의존한다고 말 했으므로 아래는 가장 일반적인 쿼리입니다.
SELECT * FROM homes
WHERE geolat BETWEEN ??? AND ???
AND geolng BETWEEN ??? AND ???
업데이트 2 :
다음 데이터베이스 스키마를 사용하십시오.
CREATE TABLE IF NOT EXISTS `homes` (
`home_id` int(10) unsigned NOT NULL auto_increment,
`primary_photo_group_id` int(10) unsigned NOT NULL default '0',
`customer_id` bigint(20) unsigned NOT NULL,
`account_type_id` int(11) NOT NULL,
`address` varchar(128) collate utf8_unicode_ci NOT NULL,
`city` varchar(64) collate utf8_unicode_ci NOT NULL,
`state` varchar(2) collate utf8_unicode_ci NOT NULL,
`zip` mediumint(8) unsigned NOT NULL,
`price` mediumint(8) unsigned NOT NULL,
`sqft` smallint(5) unsigned NOT NULL,
`year_built` smallint(5) unsigned NOT NULL,
`num_of_beds` tinyint(3) unsigned NOT NULL,
`num_of_baths` decimal(3,1) unsigned NOT NULL,
`num_of_floors` tinyint(3) unsigned NOT NULL,
`description` text collate utf8_unicode_ci,
`geolat` decimal(10,6) default NULL,
`geolng` decimal(10,6) default NULL,
`display_status` tinyint(1) NOT NULL,
`date_listed` timestamp NOT NULL default CURRENT_TIMESTAMP,
`contact_email` varchar(100) collate utf8_unicode_ci NOT NULL,
`contact_phone_number` varchar(15) collate utf8_unicode_ci NOT NULL,
PRIMARY KEY (`home_id`),
KEY `customer_id` (`customer_id`),
KEY `city` (`city`),
KEY `num_of_beds` (`num_of_beds`),
KEY `num_of_baths` (`num_of_baths`),
KEY `geolat` (`geolat`),
KEY `geolng` (`geolng`),
KEY `account_type_id` (`account_type_id`),
KEY `display_status` (`display_status`),
KEY `sqft` (`sqft`),
KEY `price` (`price`),
KEY `primary_photo_group_id` (`primary_photo_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=8 ;
다음 SQL 사용
EXPLAIN SELECT homes.home_id,
address,
city,
state,
zip,
price,
sqft,
year_built,
account_type_id,
num_of_beds,
num_of_baths,
geolat,
geolng,
photo_id,
photo_url_dir
FROM homes
LEFT OUTER JOIN home_photos ON homes.home_id = home_photos.home_id
AND homes.primary_photo_group_id = home_photos.home_photo_group_id
AND home_photos.home_photo_type_id = 2
WHERE homes.display_status = true
AND homes.geolat BETWEEN -100 AND 100
AND homes.geolng BETWEEN -100 AND 100
EXPLAIN은 다음을 반환합니다.
id select_type table type possible_keys key key_len ref rows Extra
----------------------------------------------------------------------------------------------------------
1 SIMPLE homes ref geolat,geolng,display_status display_status 1 const 2 Using where
1 SIMPLE home_photos ref home_id,home_photo_type_id,home_photo_group_id home_photo_group_id 4 homes.primary_photo_group_id 4
EXPLAIN 명령을 읽는 방법을 잘 모르겠습니다. 이것이 좋거나 나빠 보입니까? 현재 geolat 및 geolng에 복합 인덱스를 사용하지 않습니다. 내가해야합니까?
답변
이점이있는 쿼리를 사용할 때는 복합 인덱스를 사용해야합니다. 다음과 같은 복합 인덱스 :
index( column_A, column_B, column_C )
이러한 필드를 사용하여 조인, 필터링 및 때로는 선택하는 쿼리에 도움이됩니다. 또한 해당 컴포지트에서 열의 가장 왼쪽에있는 하위 집합을 사용하는 쿼리에도 도움이됩니다. 따라서 위의 색인은 필요한 쿼리를 만족시킵니다.
index( column_A, column_B, column_C )
index( column_A, column_B )
index( column_A )
그러나 필요한 쿼리에는 도움이되지 않습니다 (적어도 직접적이지는 않지만 더 나은 지수가 없으면 부분적으로 도움이 될 수 있음)
index( column_A, column_C )
column_B가 어떻게 누락되었는지 확인하십시오.
원래 예에서 2 차원의 복합 색인은 대부분의 차원이나 가장 왼쪽의 차원을 쿼리하지만 가장 오른쪽의 차원 자체는 쿼리하지 않는 쿼리에 주로 도움이됩니다. 항상 2 차원을 쿼리하는 경우 복합 색인을 사용하는 것이 가장 중요합니다 (아마도 가장 먼저).
답변
다음과 같은 세 가지 쿼리가 있다고 가정합니다.
쿼리 I :
SELECT * FROM homes WHERE `geolat`=42.9 AND `geolng`=36.4
쿼리 II :
SELECT * FROM homes WHERE `geolat`=42.9
쿼리 III :
SELECT * FROM homes WHERE `geolng`=36.4
열당 별도의 인덱스가있는 경우 세 쿼리 모두 인덱스를 사용합니다. MySQL에서 복합 인덱스 ( geolat
, geolng
)가있는 경우 쿼리 I 및 쿼리 II (복합 인덱스의 첫 번째 부분을 사용) 만 인덱스를 사용합니다. 이 경우 쿼리 III에는 전체 테이블 검색이 필요합니다.
에 다중 열 인덱스의 설명서의 부분, 내가 설명서를 다시 입력하지 않아도 여러 열 인덱스가 어떻게 작동하는지 설명 명확하게된다.
로부터 MySQL을 참조 설명서 페이지 :
다중 컬럼 인덱스는 인덱스 컬럼의 값을 연결하여 작성된 값을 포함하는 정렬 된 배열로 간주 될 수 있습니다 .
geolat 및 geolng 열에 분리 된 인덱스를 사용하는 경우 테이블에 독립적으로 검색 할 수있는 두 개의 다른 인덱스가 있습니다.
INDEX geolat
-----------
VALUE RRN
36.4 1
36.4 8
36.6 2
37.8 3
37.8 12
41.4 4
INDEX geolng
-----------
VALUE RRN
26.1 1
26.1 8
29.6 2
29.6 3
30.1 12
34.7 4
복합 색인을 사용하는 경우 두 열 모두에 대해 하나의 색인 만 있습니다.
INDEX (geolat, geolng)
-----------
VALUE RRN
36.4,26.1 1
36.4,26.1 8
36.6,29.6 2
37.8,29.6 3
37.8,30.1 12
41.4,34.7 4
RRN은 상대 레코드 번호입니다 (간단히 말하면 ID를 말할 수 있음). 처음 두 인덱스는 별도로 생성되고 세 번째 인덱스는 복합입니다. 보시다시피 geolat에 의해 색인화되어 있기 때문에 geolng를 기준으로 검색 할 수 있지만 geolng는 2 단계 색인이므로 geolat 또는 “geolat AND geolng”로 검색 할 수 있습니다.
또한 MySQL이 인덱스를 사용 하는 방법 매뉴얼 섹션을 살펴보십시오 .
답변
복합 인덱스의 기능에 대한 오해가있을 수 있습니다. 많은 사람들이 지수가 긴만큼 검색 쿼리를 최적화 할 수 있다고 생각 where
조항은 귀하의 경우, 인덱스 컬럼을 포함 geolat
하고 geolng
. 더 깊이 탐구합시다 :
가정의 좌표에 대한 데이터는 다음과 같이 임의의 소수입니다.
home_id geolat geolng
1 20.1243 50.4521
2 22.6456 51.1564
3 13.5464 45.4562
4 55.5642 166.5756
5 24.2624 27.4564
6 62.1564 24.2542
...
그 이후 geolat
로 geolng
가치는 거의 반복되지 않습니다. 에 지수 geolat
와 geolng
같이 보일 것입니다 :
index_id geolat geolng
1 20.1243 50.4521
2 20.1244 61.1564
3 20.1251 55.4562
4 20.1293 66.5756
5 20.1302 57.4564
6 20.1311 54.2542
...
따라서 복합 인덱스의 두 번째 열은 기본적으로 쓸모 가 없습니다 ! 복합 인덱스를 사용한 쿼리 속도는 아마도 geolat
열의 인덱스와 비슷할 것 입니다.
Will이 언급했듯이 MySQL은 공간 확장 지원을 제공합니다 . 공간 포인트는 두 개의 개별 lat
lng
열 대신 단일 열에 저장됩니다 . 이러한 컬럼에 공간 인덱스를 적용 할 수 있습니다. 그러나 내 개인적인 경험에 따라 효율성이 과대 평가 될 수 있습니다. 공간 인덱스는 2 차원 문제를 해결하지 않고 2 차 분할을 사용하는 R- 트리를 사용하여 검색 속도를 높이는 것일 수 있습니다.
단점 은 좌표 저장에 8 바이트 배정도 숫자를 사용했기 때문에 공간 포인트가 훨씬 더 많은 메모리 를 소비 한다는 것 입니다. 내가 틀렸다면 나를 바로 잡으십시오.
답변
복합 인덱스는 다음과 같이 매우 강력합니다.
- 구조 무결성 강화
- FILTERED ID에서 정렬 사용
구조적 무결성 강화
복합 색인은 다른 유형의 색인이 아닙니다. 무결성을 기본 키로 적용하여 테이블에 NECESSARY 구조를 제공 할 수 있습니다.
MySQL의 Innodb는 클러스터링을 지원하며 다음 예제는 복합 인덱스가 필요한 이유를 보여줍니다.
친구 테이블 (예 : 소셜 네트워크)을 만들려면 2 개의 열이 필요합니다 user_id, friend_id
.
테이블 구조
user_id (medium_int)
friend_id (medium_int)
Primary Key -> (user_id, friend_id)
기본적으로 기본 키 (PK)는 고유하며 복합 PK를 생성하여 Innodb는 user_id, friend_id
새 레코드가 추가 될 때 중복이 존재 하지 않는지 자동으로 확인합니다 . friend_id = 2
예를 들어 사용자가 둘 이상의 레코드 (관계 링크)를 가져서는 안되기 때문에 이것은 예상 된 동작 입니다.
복합 PK가 없으면 대리 키를 사용하여이 스키마를 만들 수 있습니다.
user_friend_id
user_id
friend_id
Primary Key -> (user_friend_id)
이제 새 레코드가 추가 될 때마다 조합 user_id, friend_id
이 포함 된 이전 레코드가 없는지 확인해야 합니다.
따라서 복합 인덱스는 구조 무결성을 강화할 수 있습니다.
필터링 된 ID에서 정렬 가능
게시물 시간 (타임 스탬프 또는 날짜 / 시간)별로 레코드 집합을 정렬하는 것이 매우 일반적입니다. 일반적으로 이것은 주어진 ID에 게시하는 것을 의미합니다. 여기에 예가 있습니다
User_Wall_Posts 테이블 (Facebook의 벽 게시물인지 생각)
user_id (medium_int)
timestamp (timestamp)
author_id (medium_int)
comment_post (text)
Primary Key -> (user_id, timestamp, author_id)
우리는 (날짜) user_id = 10
별로 댓글 게시물에 대한 모든 게시물을 쿼리하고 찾고 싶습니다 timestamp
.
SQL 쿼리
SELECT * FROM User_Wall_Posts WHERE user_id = 10 ORDER BY timestamp DES
복합 PK를 통해 Mysql은 색인을 사용하여 결과를 필터링하고 정렬 할 수 있습니다. MySQL은 결과를 가져 오기 위해 임시 파일이나 파일 정렬을 사용할 필요가 없습니다. 복합 키가 없으면 이것이 불가능하며 매우 비효율적 인 쿼리를 유발할 수 있습니다.
따라서 복합 키는 매우 강력하며 “검색을 원 column_a, column_b
하므로 복합 키를 사용할 것 입니다.”라는 단순한 문제보다 더 적합 합니다. 현재 데이터베이스 스키마에는 단일 키만큼 많은 복합 키가 있습니다. 간과하지 마십시오. 복합 키 사용!
답변
복합 인덱스 는 다음에 유용합니다.
- 0 개 이상의 “=”절과
- 최대 하나의 범위 절.
복합 인덱스는 두 범위를 처리 할 수 없습니다 . 인덱스 쿡북 에서 더 자세히 설명하겠습니다 .
가까운 찾기 – 질문 인 경우 정말 최적화에 대해
WHERE geolat BETWEEN ??? AND ???
AND geolng BETWEEN ??? AND ???
다음 아무 지수는 정말 두 차원을 처리 할 수 없습니다.
대신, ‘상자 밖으로 생각해야’합니다. 분할을 통해 한 차원을 구현하고을 신중하게 선택하여 다른 차원을 구현하면 PRIMARY KEY
매우 큰 위도 / 경도 조회 테이블의 효율성이 크게 향상 될 수 있습니다. 내 latlng 블로그 는 전 세계에서 “가장 가까운 위치 찾기”를 구현하는 방법에 대해 자세히 설명합니다. 코드가 포함되어 있습니다.
는 PARTITIONs
위도 범위의 줄무늬입니다. 는 PRIMARY KEY
의도적 때문에 유용 행은 동일한 블록에있을 가능성이 높다는 경도 시작한다. Stored Routine order by... limit...
은 충분한 커피 숍 (또는 무엇이든)이 생길 때까지 대상 주변에서 ‘사각형’ 을 만들고 늘리기 위한 지저분한 코드를 오케스트레이션합니다 . 또한 대원 계산을 처리하고 날짜 표시 줄과 극점을 처리합니다.
더
다른 블로그를 작성했습니다. : 그것은 위도 / 일 검색 LNG의 5 가지 비교 http://mysql.rjweb.org/doc.php/latlng#representation_choices을 다른 방법 중 하나이며,이 (이것은 제 중 하나로서 상기 소정의 링크를 참조) 그리고 특정 경우에 가장 적합 하다고 지적합니다 .
INDEX(geolat, geolng),
INDEX(geolng, geolat)
두 지수 모두 열을 가지고하고, 그 되지 geolat 및 geolng에 단일 열 인덱스를 가지는 것이 중요합니다.
답변
흑백은 없으며 한 가지 크기가 모든 답에 적합합니다.
쿼리 작업로드가 이점을 얻을 때 복합 인덱스를 사용해야합니다.
이를 판별하기 위해 조회 작업로드를 프로파일 링해야합니다.
복합 인덱스는 해당 인덱스에서 쿼리를 완전히 만족시킬 수있을 때 작동합니다.
업데이트 (게시 된 질문에 대한 편집에 대한 응답으로) : 표에서 *를 선택하면 복합 색인이 사용될 수 있습니다. EXPLAIN PLAN 을 실행 하여 확인해야합니다.
답변
공간 검색을 수행하려면 지리적 영역을 매우 빠르게 검색 할 수 있는 R- 트리 알고리즘 이 필요합니다 . 이 직업에 꼭 필요한 것.
일부 데이터베이스에는 공간 인덱스가 내장되어 있습니다. 빠른 Google 검색을 통해 MySQL 5에 MySQL이 있음을 알 수 있습니다 (SQL을 보면 MySQL을 사용하고 있다고 생각합니다).