2016-08-24 49 views
1

我有一個複雜的C#程序,它使用動態構建的查詢從SQLite數據庫中讀取。 當我在調試器下運行程序,我注意到,我得到的大量輸出,如:當字段是表的主鍵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爲主鍵創建了索引,那爲什麼要創建另一個?

此外,在一個相關的說明,我得到了很多關於子查詢的自動索引警告。例如,在查詢:

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 

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

EXPLAIN的查詢產生查詢計劃:

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=?) 

我想SQLite是沒有足夠的智慧認識到,子查詢不需要進入臨時表?

是否有任何重寫查詢的方法,以避免子查詢?

+0

出於好奇,你爲什麼要使用VARCHAR爲您的主鍵?這將導致列值存儲兩次,一次在b-tree中,一次在表中。我建議使用整數主鍵並將文本存儲在單獨的列中。如果需要,您仍然可以在其他列上設置唯一的約束。 – seairth

+0

你是說在文本上創建唯一索引所需的空間比以文本作爲主鍵的空間要少? –

+0

不,在這兩種情況下,最後都會出現一個包含文本副本的B樹。我更關心使用varchar作爲主鍵。在回答中繼續發表評論... – seairth

回答

1

A 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列)成爲一個單獨的列。如果這很重要,可以添加一個唯一的約束。
  • 在您的子表中,使用整數ID而不是varchar列。另外,在該列上添加一個外鍵。

的幾個注意事項:

  • MyTable使用整數主鍵和移動VARCHAR到具有唯一約束單獨列將作出的MyTable大小沒有區別。正如我上面提到的,主鍵列將是內部rowid列的別名,因此您並不真正添加任何新列。
  • 通過將子表切換爲使用整數作爲外鍵,這將導致更小的表。即使添加了外鍵約束,您的數據庫也會比現在更小。這也應該使你的聯接更快(對於大數據集,無論如何)。
+0

varchar key字段實際上不超過4個字符,所以我懷疑在我的特殊情況下節省空間會很小。而選擇Subtable.ArrangementId的其他查詢會增加複雜性(因爲必須向連接添加連接)。所以我不會接受這個答案。 –