2011-08-11 6 views
0

나는 H2를 사용하고 있으며 다래 대 관계를 통해 연결된 자체 (저널 엔트리)와 저자 (테이블 Persons) 테이블에 저자. 데이터베이스가 상당히 큽니다 (900'000 명 + 2.5M + 권).H2에서 다 대다 관계에서 효율적으로 선택

이름이 패턴 (LIKE '% pattern %')과 일치하는 저자가 한 명 이상인 모든 도서의 목록을 효율적으로 선택하려고합니다. 여기의 트릭은 패턴이 일치하는 저자의 수를 엄하게 제한해야하며 각 저자는 합리적으로 적은 수의 관련 서적을 가지고 있어야한다는 것입니다. ,

SELECT p.*, e.title FROM Persons AS p 
    INNER JOIN Authorship AS au ON au.authorId = p.id 
    INNER JOIN Entries AS e ON e.id = au.entryId 
WHERE p.name like '%pattern%'; 

가 나는 저자의 아주 작은 (하위) 테이블에 합류 해요로 첫 번째는, 훨씬 빠른 것으로 예상 :

SELECT p.*, e.title FROM (SELECT * FROM Persons WHERE name LIKE '%pattern%') AS p 
    INNER JOIN Authorship AS au ON au.authorId = p.id 
    INNER JOIN Entries AS e ON e.id = au.entryId; 

과 :

나는 두 개의 쿼리를 시도 그러나 둘 다 오래 걸립니다. 실제로 필자는 쿼리를 수동으로 세 가지 선택으로 분해하고 원하는 결과를 더 빨리 찾을 수 있습니다.

쿼리를 설명하려고 할 때 실제로는 테이블과 WHERE 절에 대한 전체 조인과 비슷하다는 것을 알게되었습니다. 따라서 제 질문은 : 어떻게하면 빠른 선택을 얻을 수 있습니까? 저자의 필터가 다른 두 테이블과 훨씬 더 작은 조인을 가져야한다는 사실에 대해서?

MySQL에서 동일한 쿼리를 시도하고 예상했던 것과 일치하는 결과를 얻었음에 유의하십시오 (먼저 선택하는 것이 훨씬 빠름).

감사합니다.

+1

첫 번째 JOIN에서 SUBSELECT 인 이유는 무엇입니까? 단순히 'INNER JOIN authorship AS au ON ...'이 아닌가? – wonk0

+0

네가 맞아, 나는 변화를 만들었다. 쿼리는 같은 것 (적어도 EXPLAIN에 따르면)으로 변환되지만 이제는 더 간단합니다. 감사합니다. – Philippe

+0

이러한 쿼리에 대한'EXPLAIN ANALYZE SELECT ... '의 결과는 무엇입니까? –

답변

1

좋아, 여기에 마침내 나를 위해 일한 것입니다.

대신 쿼리 실행의 :

SELECT p.*, e.title FROM (SELECT * FROM Persons WHERE name LIKE '%pattern%') AS p 
    INNER JOIN Authorship AS au ON au.authorId = p.id 
    INNER JOIN Entries AS e ON e.id = au.entryId; 

을 ... 나는 달렸다 :

SELECT title FROM Entries e WHERE id IN (
    SELECT entryId FROM Authorship WHERE authorId IN (
    SELECT id FROM Persons WHERE name LIKE '%pattern%' 
) 
)   

그것은 정확히 같은 쿼리 아니다, 지금은 저자의 ID로를하지 않기 때문에 결과의 열은 원했지만 원하는 것입니다. 패턴이 작성자의 수를 매우 작은 값으로 제한하여 적은 수의 항목을 통해서만 검색한다는 사실을 이용하십시오.

흥미로운 점은 이것이 H2와 함께 훌륭하게 작동한다는 것입니다 (조인보다 훨씬 빠릅니다). 그러나 MySQL에서는 매우 느립니다. (이것은 LIKE '% pattern %'부분과 아무런 관련이 없으며, 다른 답변의 주석을 참조하십시오.) 쿼리가 다르게 최적화되었다고 가정합니다.

+1

니스. MySQL이 바깥 쿼리에 대해 매번 서브 쿼리를 평가하기 때문에 결과를 "기억"하지 못하기 때문에 MySQL에 정말 좋지 않을 것입니다. 알려진 약점. 3 레벨의 중첩을하면 많은 상처를 입을 것입니다 :-) – Brian

+0

감사합니다. – Philippe

0

SELECT * FROM Persons WHERE name LIKE '%pattern%'는 관계없이 항상 당신이 % MySQL을 사용하여 패턴 '%pattern%' 시작은 어떤 인덱스를 사용할 수 없으며 전체 테이블 스캔을해야 할 때 때문에 할 어떤 900,000+ 행 테이블에 오랜 시간이 걸리지 않을 것이다. full-text indexes and function을 조사해야합니다.

+0

사실 저 속도는 아니며, 적어도 내 목적에 맞지 않습니다. (hoppa의 대답을보십시오). 링크를 가져 주셔서 감사합니다. – Philippe

0

같은 조건이 와일드 카드로 시작하기 때문에 전체 테이블 스캔이 항상 느려지 며 내부 캐시가 수행되지 않습니다.

전체 텍스트 검색을 원하면 mysql이 최선의 방법은 아닙니다. 이러한 종류의 문제를 해결하려면 다른 소프트웨어 (예 : solr)를 살펴보십시오.

+0

두 가지 : 1) 주로 H2를 사용하고 있습니다. 비교를 위해서만 MySQL을 사용하고 있었는데 아마도 그 태그를 제거해야 할 것입니다. 2) SELECT * FROM Person을 WHERE name LIKE '% pattern %'로 실행하면 합리적으로 빠른 결과를 얻습니다. (H2로 반 초, MySQL의 1/10) 결과에 몇 개의 항목이 있습니다. 진정한 질문은이 몇 권의 저서와 관련된 책을 어떻게 빨리 얻을 수 있는가하는 것입니다. – Philippe

관련 문제