2013-04-14 3 views
2

나는 사전을위한 복잡한 데이터베이스 스키마를 가지고있다. 키워드 중 하나에 자신을 속할 수관계형 데이터베이스에서 개체를 모델링하고 쿼리하는 방법은 무엇입니까?

Entry { 
    keyword; 
    examples; 
    tags; 
    Translations; 
} 

Translation { 
    text; 
    tags; 
    examples; 
} 

Example { 
    text; 
    translation; 
    phonetic_script; 
} 

즉, 태그 (즉, 문법)

로, 또는 각 객체 (본질적으로 번역)이 유사하다 번역 (외국어의 문법) 및 유사한 예는 번역 자체 (외국어 설명) 또는 항목의 텍스트에 속할 수 있습니다. 그런 종류의 관계형 디자인으로 끝났습니다.

entries(id,keyword,) 
tags(tag) 
examples(id,text,...) 
entrytags(entry_id,tag) 
entryexamples(entry_id,example_id) 
translations(id,belongs_to_entry,...) 
translationtags(transl_id, tag) 
translationexamples(transl_id,example_id) 

내 주요 작업은이 데이터베이스를 쿼리합니다. "foo"를 검색한다고 가정 할 때 현재 처리 방법은 다음과 같습니다.

query all entries with foo, get ids A 
foreach id in A 
    query all examples belonging to id 
    query all tags belonging to id 
    query all translations belonging to A, store their ids in B 
    foreach tr_id in B 
     query all tags belonging to tr_id 
     query all examples belonging to tr_id 

내 개체를 다시 작성하십시오. 이것은 나에게 성 가시고, 느립니다. 조인이나 다른 방법을 사용하여이 문제를 크게 개선 할 수있는 방법이 없습니다. 데이터베이스의 관계에 이러한 개체를 모델링하는 데 어려움이 있습니다. 이것은 적절한 설계입니까?

어떻게하면 쿼리 시간을 개선하는 데 더 효율적이 될 수 있습니까?

+0

NoSQL과 같은 다른 데이터베이스 솔루션을 고려해보십시오. RDBMS는 모든 솔루션입니다. – Amirshk

답변

1

루프에서 호출되는 각 쿼리는 사소한 쿼리의 경우에도 최소한 실행 시간을 기본으로합니다. 많은 환경 요소가이 지속 시간에 기여하지만 이제는 10 밀리 초라고 가정합시다. 첫 번째 쿼리가 100 개의 항목과 일치하면 호출되는 총 쿼리 수는 총 301 개 (각각 10 밀리 초, 총 3 초)입니다. 루프 반복 횟수가 다양하기 때문에 성능이 크게 변할 수 있습니다.

조인을 사용하여 쿼리를 재구성하면 더 복잡한 쿼리가 만들어 지지만 호출되는 쿼리의 총 수는 고정 된 수 (아래 쿼리에서 4 개)로 줄일 수 있습니다. 이제는 더 복잡하고 총 지속 시간이 200ms가되어 이제는 각 쿼리가 실행될 때 50ms가 걸리며 3000ms가 크게 감소한다고 가정합니다.

아래에 표시된 4 개의 쿼리는 원하는 결과를 얻는 데 거의 가깝습니다. 하위 쿼리를 사용하거나 FROM 절에 테이블을 포함하는 것과 같은 쿼리를 작성하는 다른 방법이 있지만 JOIN을 사용하여 쿼리를 수행하는 방법을 보여줍니다. 조건 entries.keyword = 'foo'은 항목을 선택하기 위해 원래 쿼리의 조건을 나타내는 데 사용됩니다.

entries의 조건이 매우 높으면 성능을 향상시키기 위해 다른 최적화가 필요할 수 있습니다 이 예제에서 조건은 인덱스에서 빨리 검색하는 간단한 비교이지만 전체 테이블 스캔이 필요할 수있는 LIKE을 사용하면 이러한 쿼리에서 제대로 작동하지 않을 수 있습니다.

다음 쿼리는 원래 쿼리와 일치하는 모든 예제를 선택합니다. 원래 쿼리의 조건은 entries.keyword 열에 WHERE 절로 표시됩니다.

SELECT entries.id, examples.text 
    FROM entries 
INNER JOIN entryexamples 
    ON (entries.id = entryexamples.entry_id) 
INNER JOIN examples 
    ON (entryexamples.example_id = examples.id) 
WHERE entries.keyword = 'foo'; 

이 쿼리는 원래 쿼리와 일치하는 태그를 선택합니다. 이 경우에는 entrytags.tag 열이 필요하고 tags과 조인하면 동일한 값만 제공되기 때문에 두 개의 조인 만 사용됩니다.

SELECT entries.id, entrytags.tag 
    FROM entries 
INNER JOIN entrytags 
    ON (entries.id = entrytags.entry_id) 
WHERE entries.keyword = 'foo''; 

이 쿼리는 원래 쿼리의 변환 태그를 선택합니다. 이것은 entrytags을 선택하는 이전 쿼리와 비슷하지만 여기서 다른 조인 계층이 변환에 사용됩니다.

SELECT entries.id, translationtags.tag 
    FROM entries 
INNER JOIN translations 
    ON (entries.id = translations.belongs_to_entry) 
INNER JOIN translationtags 
    ON (translations.id = translationtags.transl_id) 
WHERE entries.keyword = 'foo'; 

마지막 쿼리는 examples에 대한 첫 번째 쿼리와 같은 일뿐만 아니라 추가 조인이 포함되어 있습니다. 그것은 많은 조인이 될 것이지만, 일반적으로 루핑을 통해 개별 쿼리를 실행하는 것보다 훨씬 더 잘 수행되어야합니다.

SELECT entries.id, examples.text 
    FROM entries 
INNER JOIN translations 
    ON (entries.id = translations.belongs_to_entry) 
INNER JOIN translationexamples 
    ON (translations.id = translationexamples.transl_id) 
INNER JOIN examples 
    ON (translationexamples.example_id = examples.id) 
WHERE entries.keyword = 'foo'; 
관련 문제