MySQL에서 조건부 인덱스를 만드는 방법은 무엇입니까?


24

MySQL에서 테이블의 특정 범위 또는 하위 집합을 필터링하기 위해 인덱스를 만드는 방법은 무엇입니까? AFAIK 직접 만들 수는 없지만이 기능을 시뮬레이션 할 수 있다고 생각합니다.

예 : NAME열이있는 행에 대해서만 인덱스를 만들고 싶습니다.STATUS = 'ACTIVE'

이 기능 을 SQL Server 에서는 필터링 된 인덱스 라고하며 Postgres 에서는 부분 인덱스 라고합니다 .

답변:


9

MySQL은 현재 조건부 인덱스를 지원하지 않습니다.

당신이 요구하는 것을 달성하기 위해 (당신이하지 않아야합니다;) 보조 테이블 만들기를 시작할 수 있습니다 :

CREATE TABLE  `my_schema`.`auxiliary_table` (
   `id` int unsigned NOT NULL,
   `name` varchar(250), /* specify the same way as in your main table */
   PRIMARY KEY (`id`),
   KEY `name` (`name`)
);

그런 다음 기본 테이블에 세 개의 트리거를 추가하십시오.

delimiter //

CREATE TRIGGER example_insert AFTER INSERT ON main_table
FOR EACH ROW
BEGIN
   IF NEW.status = 'ACTIVE' THEN
      REPLACE auxiliary_table SET
         auxiliary_table.id = NEW.id,
         auxiliary_table.name = NEW.name;
   END IF;
END;//

CREATE TRIGGER example_update AFTER UPDATE ON main_table
FOR EACH ROW
BEGIN
   IF NEW.status = 'ACTIVE' THEN
      REPLACE auxiliary_table SET
         auxiliary_table.id = NEW.id,
         auxiliary_table.name = NEW.name;
   ELSE
      DELETE FROM auxiliary_table WHERE auxiliary_table.id = OLD.id;
   END IF;
END;//

CREATE TRIGGER example_delete AFTER DELETE ON main_table
FOR EACH ROW
BEGIN
   DELETE FROM auxiliary_table WHERE auxiliary_table.id = OLD.id;
END;//

delimiter ;

트리거 내부에서 delimiter //사용하고 싶기 때문에 필요 ;합니다.

이렇게하면 보조 테이블에 트리거에 의해 업데이트되는 문자열 "ACTIVE"가 포함 된 기본 테이블 행에 해당하는 ID가 정확하게 포함됩니다.

에 그것을 select사용하려면 평소를 사용할 수 있습니다 join.

SELECT main_table.* FROM auxiliary_table LEFT JOIN main_table
   ON auxiliary_table.id = main_table.id
   ORDER BY auxiliary_table.name;

기본 테이블에 이미 데이터가 포함되어 있거나 비정상적인 방식으로 데이터를 변경하는 외부 작업을 수행하는 경우 (EG : 외부 MySQL) 다음과 같이 보조 테이블을 수정할 수 있습니다.

INSERT INTO auxiliary_table SET
   id = main_table.id,
   name = main_table.name,
   WHERE main_table.status="ACTIVE";

성능에 대해서는 삽입, 업데이트 및 삭제 속도가 느려질 수 있습니다. 원하는 조건이 긍정적 인 경우를 거의 다루지 않는 경우에만 의미가 있습니다. 그럼에도 불구하고, 아마도 테스트 한 것만으로도 절약 된 공간이 실제로이 aproach를 정당화하는지 (그리고 실제로 공간을 절약하고 있는지) 알 수 있습니다.


7

경우 내가 제대로 질문을 이해, 나는 당신이 뭘 하려는지 달성 할 것은 열 이름과 상태 모두에 인덱스를 생성하는 것입니다 생각합니다. 그러면 NAME = 'SMITH'및 STATUS = 'ACTIVE'위치를 효율적으로 쿼리 할 수 ​​있습니다.


1
좋습니다. 그러나 상태가 ACTIVE 인 라인이 상대적으로 적 으면 공간 효율적이지 않습니다.
Maniero

아니요, 그렇지는 않지만 문제의 요구 사항은 아니며 테이블이 값 중 하나에 크게 가중치가 부여되었다고 언급되지 않았습니다. 이를 위해 찾고있는 STATUS에 대한 구체화 된 뷰를 만들지 만 MySQL은이를 지원하지 않습니다.
BlackICE

디스크 공간이 저렴합니다.
BlackICE

2
예, 그것은 직접적인 요구 사항이 아니므로 OK로 의견을 시작했습니다. 전문적인 대안을 찾고 있습니다. 그리고 전문적인 대안은 항상 작업을 수행하는 가장 효율적인 방법을 찾고 있습니다. 당신의 대답은 아마도 가장 명백한 것입니다. 아무 문제 없습니다. 그러나 나는 "디스크 공간이 저렴하다"라는 것에 완전히 동의하지 않는다. 비싸기 때문이 아니라 물론 싸다. 그러나 메모리가 그렇게 저렴하지는 않다. 디스크 액세스는 그렇게 저렴하지 않습니다. 당신의 대답은 확실히 목표를 달성하는 올바른 방법 중 하나이지만 그것이 최선이라고 생각합니다.
Maniero

나는 또한 메모리에 동의하지 않을 것입니다. 요즘은 꽤 저렴합니다. (디스크 공간만큼 저렴하지는 않지만 일부는 10 / gig에 약간의 비용을 낼 수 있습니다.)
BlackICE

6

조건부 인덱싱은 수행 할 수 없지만 예를 들어 ( name, status) 에 여러 열 인덱스를 추가 할 수 있습니다 .

해당 열의 모든 데이터를 색인화하더라도 "active"상태로 찾고있는 이름을 찾는 데 도움이됩니다.


4

모든 데이터가 필요할 때 뷰를 사용하여 두 테이블을 통합하고 해당 열의 테이블 중 하나만 인덱싱하여 두 테이블로 데이터를 분할하면이 작업을 수행 할 수 있습니다. 그러나 이것이 필요한 쿼리의 성능 문제를 일으킬 것이라고 생각합니다 쿼리 플래너가 내가 인정한 것보다 더 영리하지 않으면 전체 테이블을 실행하십시오. 기본적으로 테이블을 수동으로 분할하고 인덱스를 하나의 파티션에만 적용합니다.

불행히도 내장 테이블 파티셔닝 기능 은 단일 파티션에 인덱스를 적용 할 수 없으므로 퀘스트에 도움이되지 않습니다.

인덱스가있는 추가 열을 유지 관리 할 수 ​​있으며 인덱스의 기반이되는 조건이 true 일 때만 해당 열에 값을 가질 수 있지만 이는 노동 집약적이며 쿼리 효율성 및 공간 절약.


조인이 여전히 비싸지 않기 때문에 더 나은 인덱싱을하기 위해 두 개의 테이블을 가지지 않을 것입니까?
jcolebrand

@jcolebrand : 일반적인 쿼리의 경우 비용이 많이 들며 (통합을 수행하는보기보다) 인덱스를 사용하려면 파티션 테이블에서 구체적으로 선택해야합니다. 내장 파티셔닝은이를 효율적으로 수행하지만, 파티션 특정 인덱스를 지원하는 경우 Bigown이 원하는 방식 (공간 절약) 만합니다. 나는 그가 할 수 있는 것이 아니라 그가 할 수 있다고 말했습니다 !
David Spillett

0

MySQL은 이제 인덱스에 사용할 수있는 가상 열을가집니다.


3
이 기능을 사용하여 필터링 된 인덱스를 시뮬레이션 할 수 있습니까?
ypercubeᵀᴹ

1
@ yper-trollᵀᴹ, druud62는 Oracle을 생각하고있을 것입니다 : dbfiddle.uk/… — MySQL은 다음과 같은 방식으로 NULL을 처리하는 것으로 보이지 않습니다 : dbfiddle.uk/…
Jack Douglas

아마 @JackDouglas. (그런 식으로 공간을 절약하는 인덱스 최적화가 아닌가? 다른 말로 select count(*) from foo where id is null ;인덱스를 사용할 수 있는가?)
ypercubeᵀᴹ

@ yper-trollᵀᴹ Oracle은 모든 인덱스 열이 NULL 인 행을 인덱싱하지 않으며 ( use-the-index-luke.com/sql/where-clause/null/index ) — 가상 열이 켜져있을 수 있습니다 decode(status,'ACTIVE',name,null).
Jack Douglas

Thnx, 나는 그것이 최신 버전에서 변경되었다고 생각했습니다 (그리고 null은 색인화되었습니다).
ypercubeᵀᴹ
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.