2014-09-25 65 views
1

我加入了左邊的兩個表的連接:SQLite是使用錯誤的索引中左連接

第一個表是非常簡單

create table L (
    id integer primary key 
); 

只包含的記錄屈指可數。

第二個表是

create table R (
    L_id  null references L, 
    k  text not null, 
    v  text not null 
); 

,幷包含數百萬條記錄。

以下兩個指標都在R:

create index R_ix_1 on R(L_id); 
create index R_ix_2 on R(k); 

該SELECT語句,恕我直言,選擇了錯誤的指標:

select 
    L.id, 
    R.v 
from 
    L left join 
    R on 
     L.id = R.L_id and 
     R.k = 'foo'; 

一個explain query plan告訴我SELECT語句使用索引R_ix_2,選擇的執行需要太多時間。如果sqlite選擇使用R_ix_1代替,我相信性能會更好 。

我也

select 
    L.id, 
    R.v 
from 
    L left join 
    R indexed by R_ix_1 on 
     L.id = R.L_id and 
     R.k = 'foo'; 

嘗試,但給了我Error: no query solution

有什麼我可以做的,使SQLite使用其他索引?

+0

你確定'r_ix_1'存在並且包含你認爲它的作用嗎? – 2014-09-25 11:33:28

+0

是的,我在sqlite3提示符下用'.schema R'確認。 – 2014-09-25 11:43:39

回答

2

您的加盟條件依賴於2列,所以你的指標應包括那些2列:

create index R_ix_1 on R(L_id, k); 

如果你做一些其他的查詢只依靠單個列,您可以保留舊的索引,但你仍然需要也有這個雙列索引以及:

create index R_ix_1 on R(L_id); 
create index R_ix_2 on R(k); 
create index R_ix_3 on R(L_id, k); 
+0

我不是100%相信。當我從'R選擇*其中k =「foo」和L_id = 42'時,表現非常快,沒有建議的索引。 – 2014-09-25 12:16:47

+0

您是否嘗試在創建雙列索引的同時執行原始「連接」查詢? – Googie 2014-09-25 12:57:47

+0

還沒有,我需要等到晚上,直到我開始創建索引。 – 2014-09-25 13:12:55

1

我不知道在這種情況下SQLite優化器是否只是困惑。這是否更好?

select L.id, R.v 
from L left join 
    R 
    on L.id = R.L_id 
where R.k = 'foo' or R.k is NULL; 

編輯:

當然,如果該類型的列是相同的SQLite將只使用一個索引。該問題未指定l_id的類型。如果它與主鍵的類型不同,那麼索引(可能)將不會被使用。

+0

不,不幸的是 - '解釋查詢計劃'告訴我既不使用'r_ix_1'也不使用'r_ix_2'(或任何其他索引)。 – 2014-09-25 12:43:48

+1

@RenéNyffenegger。 。 。這兩個字段有*完全相同的類型嗎?這將是該指數無法使用的原因之一。 (您的問題省略了第一個表中的類型。) – 2014-09-25 12:48:22

+0

您的意思是,如果'L.id'與'R.L_id'具有相同的類型?不,它們不一樣,'R.L_id'沒有類型(如'.schema',如果在sqlite中有typelessnes這樣的事情),'R.L_id'是'INT',那麼你'是一個很好的,因爲我相信這種差異很可能是這種情況。讓我改變數據類型並再次測試,但這不能在今天完成。 – 2014-09-25 12:57:52