2016-08-24 2 views
1

동적으로 작성된 쿼리를 사용하여 SQLite 데이터베이스에서 읽는 복잡한 C# 프로그램이 있습니다.필드가 테이블의 기본 키인 경우 SQLite "MyTable (ID) 자동 인덱스"

SQLite warning (284): automatic index on MyTable(Id) 

내가 MyTable에 대한 스키마를 살펴 보았다, 그리고 ID가 기본 키로 지정되어,이 같은 :

내가 디버거에서 프로그램을 실행할 때 통지 , 나는 같은 출력을 많이 얻을
CREATE TABLE MyTable (Id varchar(50) collate nocase primary key not null, 
Name varchar(50) not null, 
(etc) 

SQLite는 기본 키에 대한 인덱스를 만들었다 고 생각했기 때문에 다른 키를 만드는 이유는 무엇입니까?

관련 메모에서 하위 쿼리에 대한 자동 색인 경고가 많이 나타납니다. 예를 들어, 쿼리 :

MyTable has Id as the primary key 
Organisations has Id as the primary key 
SubTable has a unique index on ArrangementId, OrganisationId 

쿼리 수익률에 쿼리 계획을 EXPLAIN

SELECT MyTable.Id, MyTable.Name, Amount 
FROM MyTable 
LEFT JOIN (SELECT ArrangementId, Amount, AgreementDate FROM SubTable 
JOIN Organisations ON Organisations.Id = SubTable.OrganisationId AND Organisations.Direction = 1 
) AS MyJoin ON MyJoin.ArrangementId = MyTable.Id 
ORDER BY Id 

: 내가 SQLite는 추측

1|0|0|SCAN TABLE SubTable 
1|1|1|SEARCH TABLE Organisations USING INDEX sqlite_autoindex_Organisations_1 (Id=?) 
0|0|0|SCAN TABLE Arrangements USING INDEX sqlite_autoindex_Arrangements_1 
0|1|1|SEARCH SUBQUERY 1 AS MyJoin USING AUTOMATIC COVERING INDEX (ArrangementId=?) 

는 하위 쿼리 것을 깨닫게만큼 똑똑하지 않다 임시 테이블에 갈 필요가 없습니까?

하위 쿼리를 피할 수 있도록 쿼리를 다시 작성할 수있는 방법이 있습니까?

+0

, 왜 사용되는 VARCHAR ? 이렇게하면 b-tree에 한 번, 테이블에 한 번 두 번 저장되는 열 값이 생깁니다. 정수 기본 키를 사용하고 텍스트를 별도의 열에 저장하는 것이 좋습니다. 원한다면 여전히 다른 컬럼에 고유 제한 조건을 설정할 수 있습니다. – seairth

+0

텍스트에 고유 인덱스를 만드는 것이 텍스트를 기본 키로 사용하는 것보다 공간을 덜 차지한다는 말입니까? –

+0

아니요, 두 경우 모두 텍스트 복사본이 포함 된 b- 트리로 끝납니다. 나는 varchar를 기본 키로 사용하는 것에 대해 더 염려했습니다. 대답에서이 의견 계속 ... – seairth

답변

1

collate nocase 열은 collate nocase 색인이됩니다. 조회에서 동일한 데이터 정렬을 사용하지 않으면 해당 색인을 사용할 수 없습니다. (해당 열의 비교는 기본적으로 nocase을 사용하지만 비교가 다른 데이터 정렬로 다른 열에 대해 수행되는 경우에는 도움이되지 않습니다.)

이 쿼리가 중요한 경우 정확한 데이터 정렬로 두 번째 인덱스를 만드는 것이 좋습니다.그것은 왼쪽 외부의 오른쪽 피연산자 조인 (rule 3)이기 때문에 두 번째 쿼리에서


, 데이터베이스 해야는 임시 테이블을 사용하여 하위 쿼리를 평가합니다.

당신은 간단한 일련의 쿼리를 다시 시도 할 수 있습니다 당신은 의미가 동일하게 유지해야하는 경우 조인 : 기본 키를

호기심에서
FROM MyTable 
LEFT JOIN SubTable ON MyTable.Id = SubTable.ArrangementId 
LEFT JOIN Organisations ON Organisations.Id = SubTable.OrganisationId 
         AND Organisations.Direction = 1 
+0

고맙습니다. 그것은 합리적인 대답 인 것 같습니다. SubTable.OrganisationId에 동일한 데이터 정렬을 설정해야합니다. 게다가 쿼리의 단순화가 좋은 것 같습니다. –

0

다음 변경을 시도해보십시오

  • 만들기 ID 정수 기본 키. 이것은 실제로 별도의 열이 아닌 내부 ROWID의 별명입니다.
  • 현재 ID (varchar 열)를 별도의 열로 만듭니다. 선택적으로 고유 제한 조건을 추가하십시오 (중요하다면).
  • 하위 테이블에서 varchar 열 대신 정수 ID를 사용하십시오. 또한 열에 외래 키를 추가하십시오.

몇 가지 참고 사항 :

  • MyTable의 정수 기본 키를 사용하고 MyTable의 크기에 차이를 만들 것 고유 제한 조건을 가진 별도의 컬럼에 VARCHAR를 이동. 위에서 언급했듯이 기본 키 열은 내부 ROWID 열의 별칭이므로 새 열을 실제로 추가하지는 않습니다.
  • 외부 테이블로 정수를 사용하도록 하위 테이블을 전환하면 더 작은 테이블이 생성됩니다. 외래 키 제약 조건을 추가하더라도 데이터베이스는 현재보다 작아집니다. 또한 조인을 더 빨리 수행해야합니다 (대용량 데이터 셋의 경우).
+0

varchar 키 필드는 실제로 4 자 이상이므로 특정 경우에는 공간 절약이 최소한으로 느껴집니다. Subtable.ArrangementId를 선택하는 다른 쿼리의 추가 복잡성은 복잡합니다 (배열에 조인을 추가하지 않아도 됨). 그래서 나는이 대답을 받아들이지 않을 것이다. –

관련 문제