2017-07-16 29 views
1

非最左邊的列MAX查詢優化SQLite的,我注意到網上關於頁面SQLite's query optimizer保證形式SELECT MAX(colA) FROM TABLE的查詢可以,如果有一個指標,其最左邊一列是colA進行優化。對指數

但是,我不太清楚使用索引來根據WHERE子句中的等式來縮小表的情況,以便索引中的下一列是我在MAX上的那一列。根據索引的結構,最大值應該可以快速訪問,作爲索引子集中滿足WHERE子句的最後一行。例如,鑑於colAcolB指數,應該可以找到SELECT MAX(colB) FROM SillyTable WHERE colA = 1不掃描與colA = 1相關聯的所有6行:

Index of SillyTable on colA, colB: 
colA colB rowid 
1  1  4 
1  2  5 
1  4  2 
1  5  8 
1  6  3  # This is the one 
2  1  1 
2  5  6 
2  8  7 

不SQLite的實際優化這樣的查詢,還是會掃描所有的行滿足WHERE條款?如果它執行掃描,我如何更改查詢以使其運行更快?

我的具體使用案例與SillyTable示例類似。我創建了以下表格:

CREATE TABLE Product(
    ProductTypeID  INTEGER NOT NULL, 
    ProductID   INTEGER NOT NULL, 
    PRIMARY KEY(ProductTypeID, ProductID), 
    FOREIGN KEY(ProductTypeID) 
    REFERENCES ProductType(ProductTypeID) 
); 

ProductTypeID對錶格並不是特別有選擇性的;我可能有許多行與ProductTypeID相同但不同的ProductIDEXPLAIN QUERY PLAN告訴我,我的查詢使用了複合主鍵會自動建立索引,但無論掃描或二進制搜索行與索引中找到的子集,這是真的:

EXPLAIN QUERY PLAN SELECT MAX(ProductID) FROM Product 
    WHERE ProductTypeID = ?; 

=> 

SEARCH TABLE Product USING COVERING INDEX sqlite_autoindex_Product_1(ProductTypeID=?) 

回答

0

這在EXPLAIN所示輸出:

 
sqlite> EXPLAIN SELECT MAX(ProductID) FROM Product WHERE ProductTypeID = ?; 
addr opcode   p1 p2 p3 p4    p5 comment  
---- ------------- ---- ---- ---- ------------- -- ------------- 
0  Init   0  17 0     00 Start at 17 
1  Null   0  1  2     00 r[1..2]=NULL 
2  OpenRead  1  3  0  k(2,,)   02 root=3 iDb=0; sqlite_autoindex_Product_1 
3  Variable  1  3  0     00 r[3]=parameter(1,) 
4  IsNull   3  13 0     00 if r[3]==NULL goto 13 
5  Affinity  3  1  0  D    00 affinity(r[3]) 
6  SeekLE   1  13 3  1    00 key=r[3]  
7  IdxLT   1  13 3  1    00 key=r[3]  
8  Column   1  1  4     00 r[4]=Product.ProductID 
9  CollSeq  0  0  0  (BINARY)  00    
10  AggStep0  0  4  1  max(1)   01 accum=r[1] step(r[4]) 
11  Goto   0  13 0     00 max() by index 
12 Prev   1  7  0     00    
13 AggFinal  1  1  0  max(1)   00 accum=r[1] N=1 
14 Copy   1  5  0     00 r[5]=r[1]  
15 ResultRow  5  1  0     00 output=r[5] 
16 Halt   0  0  0     00    
17 Transaction 0  0  1  0    01 usesStmtJournal=0 
18 Goto   0  1  0     00    

爲了使代碼生成器更簡單,SQLite總是爲聚合創建一個循環(第6到12行)。但是,對於max(),此循環在第一個成功步驟(第11行)後中止。