2010-07-02 4 views
2

열이 문자열 접두사를 포함하는 MySQL 테이블이 있습니다. 예를 들어이 접두사는 유닉스 파일 시스템의 최상위 디렉토리 수 :MySQL : 열의 내용이 문자열의 시작 부분 인 행을 효율적으로 찾습니다.

my_table:  
+---------+ 
| prefix | 
+---------+ 
| /usr/ | 
| /bin/ | 
| /var/ | 
| /lib/ | 
+---------+ 

접두사 열의 값이 시작 어디 효율적이 테이블의 모든 행을 찾는 쿼리를 작성할 수있는 방법 주어진 끈? 문자열을 주어진 예를 들어

'는/usr/빈/고양이' 나는 '는/usr/빈/고양이의 시작입니다'는/usr/'을 포함하는 행을 찾는 쿼리를 작성하는 방법 '.

내 첫번째 추측은 LIKE이 방법을 사용하는 것입니다

SELECT * FROM my_table 
WHERE '/usr/bin/cat' LIKE CONCAT(prefix, '%') 

을하지만이 쿼리는 내가 접두사 열이 인덱스를 사용하지 않을 두려워.

은 또한 다음과 같은 내놓았다 : 같거나 즉시 사전 식 순서 '는/usr/빈/고양이' 이전의 접두사를 검색

SELECT * FROM my_table 
WHERE prefix <= '/usr/bin/cat' ORDER BY prefix DESC LIMIT 1 

합니다. 그런 다음 접두어이 실제로는 '/ usr/bin/cat'으로 시작하는지 여부를 확인할 수 있습니다.

하지만 단 한 행으로 만 작동하며 이것이 최적의 솔루션인지 궁금합니다.

편집 : 나는 예를 들어 루트 디렉토리를 사용하지만 나뿐만 아니라 임의의 문자열을 처리 할 수있는 방법이 있는지 알고 싶습니다. 아마도 이러한 문자열에는 경로 구분 기호가 포함되지 않거나 접두사가 여러 수준으로 깊어 질 수 있습니다. '/ usr/lib'라고 말하십시오.

편집 : 내 두 번째 쿼리가 가짜 인 것 같습니다. '/ usr /'는 '/ usr/bin/cat'보다 작지만 '/ usr/a'도 마찬가지입니다. 이 쿼리는 여전히 대형 테이블에서 전체 테이블 스캔보다 훨씬 빠르지 만 실제로는 첫 번째 실제 접두사를 찾을 때까지 더 많은 행을 가져와야합니다.

그래서 인덱스가 이런 종류의 접두사 검색에 도움이 될 수 있지만 여전히 그것을 활용하는 최선의 방법을 모릅니다.

+0

에 대해 생각 후 * 덜 나보다 큰 * 솔루션 조금 더 당신이 상호 독점 접두사를 가지고 있지만 그것은 파일 시스템 경로의 경우 완벽한 대답 적은 다른 경우 –

답변

1

- 상황 : 문자열을자를 수있는 위치를 알 수 없습니다.

- 그러나 우리는 접두어의 최대 길이를 알아야합니다.

- 편집 :는 또한 접두사의 최소 길이를 알고 도움이 될 것이다 - 우리가 발견하지 않으려는 잘못된 반응을 많이 제거 할 수 있습니다. (최소 = 2 자).

- 색인을 사용합니다.이 예에서는 최대 8 자입니다. x = 8 - 응용 프로그램에서 이러한 SQL 쿼리를 생성하려고 시도하십시오. - 전체 테이블 스캔이 없으며 색인을 사용하는 x- 분 +1 시간입니다. 바라기를 이것은 충분히 빠를 것이다! :)

SELECT * FROM my_table WHERE prefix = '/u' 

UNION 

SELECT * FROM my_table WHERE prefix = '/us' 

UNION 

SELECT * FROM my_table WHERE prefix = '/usr' 

UNION 

SELECT * FROM my_table WHERE prefix = '/usr/' 

UNION 

SELECT * FROM my_table WHERE prefix = '/usr/b' 

UNION 

SELECT * FROM my_table WHERE prefix = '/usr/bi' 

UNION 

SELECT * FROM my_table WHERE prefix = '/usr/bin'; 
1

?을 문자열로 바꿉니다.

SELECT * 
FROM my_table 
WHERE prefix = LEFT(?, LOCATE('/', ?, '2')) 

WHERE 절에서 색인을 사용하려면 표현식의 왼쪽에 열을 유지하고 싶습니다. 비교할 상수를 얻기 위해 문자열을 조작 할 수 있습니다.

또는 응용 프로그램에서 문자열을자를 수 있습니까?

편집

당신이 어떤 접두사에 대해 작업 할 경우 많은 그냥 하나 개의 솔루션

: 절은 일정하지의 오른쪽부터,

SELECT * 
FROM my_table 
WHERE prefix = LEFT(?, LENGTH(prefix)) 

그러나,하지만 함수를 사용하면 MySQL은 모든 행을 스캔해야한다. WHERE 절을 만족시키기 위해 접 두부에 색인을 사용하지 않습니다.

이상적으로는 왼쪽에 열이 있고 오른쪽에 상수가 있어야합니다.

+0

에 이상적 경우 좋은 나타나지만 * 문자열의 시작을 포함하는 열을 찾는 좋은 방법이 있습니까? 다른 경우에는 우물? 나는 그 문자열을 미리 잘라야할지 모른다. –

+0

@Alexandre, 대답을 업데이트했습니다. –

+0

내 질문에 두 번째 쿼리는 어떻게됩니까? 나는 그것이 인덱스를 사용한다고 믿고 WHERE 절에서 비교의 오른쪽에 실제로 상수를 갖는다. –

관련 문제