2013-11-25 56 views
1

我有以下查詢的複合sql語句,我想了解是最佳索引(索引?)來創建,我應該省略哪些,因爲它們不需要,或者如果它是反生產有多個。sqlite中sql語句的最佳索引配置?

SELECT items.id, items.standard_part_number, 
items.standard_price, items.quantity, 
part_numbers.value, items.metadata, 
items.image_file_name, items.updated_at 
FROM items LEFT OUTER JOIN part_numbers ON items.id=part_numbers.item_id 
AND part_numbers.account_id='#{account_id}' 
WHERE items.standard_part_number LIKE '#{part_number}%' 
UNION ALL 
SELECT items.id, items.standard_part_number, 
items.standard_price, items.quantity, 
part_numbers.value, items.metadata, 
items.image_file_name, items.updated_at 
FROM items LEFT OUTER JOIN part_numbers ON items.id=part_numbers.item_id 
AND part_numbers.account_id='#{account_id}' 
WHERE part_numbers.value LIKE '#{part_number}%' 
ORDER BY items.standard_part_number 
LIMIT '#{limit}' OFFSET '#{offset}' 

我有以下指標,其中一些可能是不必要的或可能我會丟失索引?......還是有太多的合作對最佳性能配置更糟糕的可以嗎?

for items: 
CREATE INDEX index_items_standard_part_number ON items (standard_part_number); 

for part_numbers: 
CREATE INDEX index_part_numbers_item_id ON part_numbers (item_id); 
CREATE INDEX index_part_numbers_item_id_and_account_id on part_numbers (item_id,account_id); 
CREATE INDEX index_part_numbers_item_id_and_account_id_and_value ON part_numbers (item_id,account_id,value); 
CREATE INDEX index_part_numbers_item_id_and_value on part_numbers (item_id,value); 
CREATE INDEX index_part_numbers_value on part_numbers (value); 

更新: 爲表的模式上面

CREATE TABLE accounts (id INTEGER PRIMARY KEY,name TEXT,code TEXT UNIQUE,created_at INTEGER,updated_at INTEGER,company_id INTEGER,standard BOOLEAN,price_list_id INTEGER); 
CREATE TABLE items (id INTEGER PRIMARY KEY,standard_part_number TEXT UNIQUE,standard_price INTEGER,part_number TEXT,price INTEGER,quantity INTEGER,unit_of_measure TEXT,metadata TEXT,image_file_name TEXT,created_at INTEGER,updated_at INTEGER,company_id INTEGER); 
CREATE TABLE part_numbers (id INTEGER PRIMARY KEY,value TEXT,item_id INTEGER,account_id INTEGER,created_at INTEGER,updated_at INTEGER,company_id INTEGER,standard BOOLEAN); 
+0

顯示數據庫模式。 –

+0

已更新爲模式 – Streamline

回答

0

外連接約束連接順序列出,所以除非必要,否則你不應該使用它們。 在第二個子查詢中,WHERE part_numbers.value LIKE ...子句無論如何都會過濾掉任何不匹配的記錄,因此應該刪除該LEFT OUTER

SQLite最多可以爲每個表(子)查詢使用一個索引。 因此,爲了能夠使用相同的索引進行搜索和排序,兩個操作必須使用相同的collation。 LIKE使用不區分大小寫的排序規則,因此應聲明ORDER BY使用相同的(ORDER BY items.standard_part_number COLLATE NOCASE)。 如果零件號碼必須區分大小寫,這是不可能的。 這是不需要的,如果SQLite不實際上使用兩個相同的索引(與EXPLAIN QUERY PLAN檢查)。

在第一個子查詢中,沒有索引可用於items.standard_part_number LIKE '#{part_number}%'搜索。 你需要這樣的一個指數(需要像NOCASE):

CREATE INDEX iii ON items(standard_part_number COLLATE NOCASE); 

在第二子查詢,SQLite是可能使用part_numbers作爲外部表的加入,因爲它有兩個過濾列。 的這兩個搜索索引必須看起來像這樣(與NOCASE 第二列):

CREATE INDEX ppp ON part_numbers(account_id, value COLLATE NOCASE); 

伴隨着這些變化,查詢和EXPLAIN QUERY PLAN輸出是這樣的:

EXPLAIN QUERY PLAN 
SELECT items.id, items.standard_part_number, 
items.standard_price, items.quantity, 
part_numbers.value, items.metadata, 
items.image_file_name, items.updated_at 
FROM items LEFT OUTER JOIN part_numbers ON items.id=part_numbers.item_id 
AND part_numbers.account_id='#{account_id}' 
WHERE items.standard_part_number LIKE '#{part_number}%' 
UNION ALL 
SELECT items.id, items.standard_part_number, 
items.standard_price, items.quantity, 
part_numbers.value, items.metadata, 
items.image_file_name, items.updated_at 
FROM items JOIN part_numbers ON items.id=part_numbers.item_id 
AND part_numbers.account_id='#{account_id}' 
WHERE part_numbers.value LIKE '#{part_number}%' 
ORDER BY items.standard_part_number COLLATE NOCASE 
LIMIT -1 OFFSET 0; 
1|0|0|SEARCH TABLE items USING INDEX iii (standard_part_number>? AND standard_part_number<?) 
1|1|1|SEARCH TABLE part_numbers USING COVERING INDEX index_part_numbers_item_id_and_account_id_and_value (item_id=? AND account_id=?) 
2|0|1|SEARCH TABLE part_numbers USING INDEX ppp (account_id=? AND value>? AND value<?) 
2|1|0|SEARCH TABLE items USING INTEGER PRIMARY KEY (rowid=?) 
2|0|0|USE TEMP B-TREE FOR ORDER BY 
0|0|0|COMPOUND SUBQUERIES 1 AND 2 (UNION ALL) 

第二個子查詢不能使用索引進行排序,因爲part_numbers不是聯接中的外部表,但通過索引查找account_idvalue的加速可能大於放慢的fr om做一個明確的排序步驟。

對於這個查詢,你可以刪除這裏沒有提到的所有索引。

如果零件編號可以很敏感地搜尋情況下,你應該刪除所有的COLLATE NOCASE的東西,並用區分大小寫的搜索(partnum BETWEEN 'abc' AND 'abcz')取代LIKE搜索。

+0

感謝您提供非常詳細和翔實的答案。我現在剛剛回到我們的項目的一部分,並意識到我沒有選擇你的答案。我們不需要任何區分大小寫的搜索,所以我將留在COLLATE NOCASE條目中。 – Streamline

+0

您的答案上面有多少地圖覆蓋或沒有映射到MySQL?我們將在此解決方案中使用MySQL和SQLite,因爲我們構建了SQLite數據庫文件以便發送到移動應用程序,但我們希望現在在MySQL中維護服務器端數據庫,因爲我們將有多個服務器和多個客戶端連接到SQLite數據庫似乎不是一個好主意。我們將維護MySQL作爲主數據庫,然後爲移動應用程序構建一個副本作爲SQLite文件下載,但所有相同的索引和選擇語句優化問題都適用於這兩者。 – Streamline

+0

請參閱[documentation](https://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html) –