Android 數據庫優化 索引


在android開發中會使用到數據庫,在頻繁的查詢以及大量數據中查詢的時候速度非常緩慢,容易出現卡頓的情況,可以使用索引進行優化

 

1、索引是對數據庫表中一列或多列的值進行排序的一種結構,使用索引可快速訪問數據庫表中的特定信息。

2:原理

 索引是對數據庫表中一個或多個列(例如,user表的姓名 (name) 列)的值進行排序的結構。如果想按特定職員的姓來查找他或她,則與在表中搜索所有的行相比,索引有助於更快地獲取信息。

 例如這樣一個查詢:select * from table1 where id=10000。如果沒有索引,必須遍歷整個表,直到ID等於10000的這一行被找到為止;有了索引之后(必須是在ID這一列上建立的索引),即可在索引中查找。由於索引是經過某種算法優化過的,因而查找次數要少
   的多。可見,索引是用來定位的。
 
3、根據數據庫的功能,可以在數據庫設計器中創建三種索引:唯一索引、主鍵索引和聚集索引。
  唯一索引 
  唯一索引是不允許其中任何兩行具有相同索引值的索引。
  當現有數據中存在重復的鍵值時,大多數數據庫不允許將新創建的唯一索引與表一起保存。數據庫還可能防止添加將在表中創建重復鍵值的新數據。例如,如果在employee表中職員的姓(lname)上創建了唯一索引,則任何兩個員工都不能同姓。
  主鍵索引
  數據庫表經常有一列或多列組合,其值唯一標識表中的每一行。該列稱為表的主鍵。
  在數據庫關系圖中為表定義主鍵將自動創建主鍵索引,主鍵索引是唯一索引 的特定類型。該索引要求主鍵中的每個值都唯一。當在查詢中使用主鍵索引時,它還允許對數據的快速訪問。
  聚集索引
  在聚集索引中,表中行的物理順序與鍵值的邏輯(索引)順序相同。一個表只能包含一個聚集索引。
  如果某索引不是聚集索引,則表中行的物理順序與鍵值的邏輯順序不匹配。與非聚集索引相比,聚集索引通常提供更快的數據訪問速度。
4、索引的使用
       根據上文的分析,我們大致對什么時候使用索引有了自己的想法(如果你沒有,回頭再看一遍。。。)。一般我們需要在這些列上建立索引:
  1)在經常需要搜索的列上,這是毋庸置疑的; 
  2)經常同時對多列進行查詢,且每列都含有重復值可以建立組合索引,組合索引盡量要使常用查詢形成索引覆蓋(查詢中包含的所需字段皆包含於一個索引中,我們只需要搜索索引頁即可完成查詢)。 同時,該組合索引的前導列一定要是使用最頻繁的列。
  對於前導列的問題,在后面sqlite的索引使用介紹中還會做討論。
  3)在經常用在連接的列上,這些列主要是一些外鍵,可以加快連接的速度,連接條件要充分考慮帶有索引的表。; 
  4)在經常需要對范圍進行搜索的列上創建索引,因為索引已經排序,其指定的范圍是連續的,同樣,在經常需要排序的列上最好也創建索引。
  6)在經常放到where子句中的列上面創建索引,加快條件的判斷速度。要注意的是where字句中對列的任何操作(如計算表達式,函數)都需要對表進行整表搜索,而沒有使用該列的索引。所以查詢時盡量把操作移到等號右邊。

  對於以下的列我們不應該創建索引:
  1)很少在查詢中使用的列
  2)含有很少非重復數據值的列,比如只有0,1,這時候掃描整表通常會更有效
  3)對於定義為TEXT,IMAGE的數據不應該創建索引。這些字段長度不固定,或許很長,或許為空。
  當然,對於更新操作遠大於查詢操作時,不建立索引。也可以考慮在大規模的更新操作前drop索引,之后重新創建,不過這就需要把創建索引對資源的消耗考慮在內。總之,使用索引需要平衡投入與產出,找到一個產出最好的點。

5、 在sqlite中使用索引 

  1)Sqlite不支持聚集索引,android默認需要一個_id字段,這保證了你插入的數據會按“_id”的整數順序插入,這個integer類型的主鍵就會扮演和聚集索引一樣的角色。所以不要再在對於聲明為:INTEGER PRIMARY KEY的主鍵上創建索引。
  2)很多對索引不熟悉的朋友在表中創建了索引,卻發現沒有生效,其實這大多數和我接下來講的有關。對於where子句中出現的列要想索引生效,會有一些限制,這就和前導列有關。所謂前導列,就是在創建復合索引語句的第一列或者連續的多列。
  比如通過:  CREATE INDEX comp_ind ON table1(x, y, z)創建索引,那么x,xy,xyz都是前導列,而yz,y,z這樣的就不是。下面講的這些,對於其他數據庫或許會有一些小的差別,這里以sqlite為標准。在where子句中,
  前導列必須使用等於或者in操作,最右邊的列可以使用不等式,這樣索引才可以完全生效。同時,where子句中的列不需要全建立了索引,但是必須保證建立索引的列之間沒有間隙。舉幾個例子來看吧:

用如下語句創建索引:
CREATE INDEX idx_ex1 ON ex1(a,b,c,d,e,...,y,z);
這里是一個查詢語句:
...WHERE a=5 AND b IN (1,2,3) AND c IS NULL AND d='hello'
這顯然對於abcd四列都是有效的,因為只有等於和in操作,並且是前導列。
再看一個查詢語句:
... WHERE a=5 AND b IN (1,2,3) AND c>12 AND d='hello'
那這里只有a,b和c的索引會是有效的,d列的索引會失效,因為它在c列的右邊,而c列使用了不等式,根據使用不等式的限制,c列已經屬於最右邊。
最后再看一條:
... WHERE b IN (1,2,3) AND c NOT NULL AND d='hello'

索引將不會被使用,因為沒有使用前導列,這個查詢會是一個全表查詢。

其實除了索引,對查詢性能的影響因素還有很多,比如表的連接,是否排序等。影響數據庫操作的整體性能就需要考慮更多因素,使用更對的技巧,不得不說這是一個很大的學問。

最后在android上使用sqlite寫一個簡單的例子,看下索引對數據庫操作的影響。
創建如下表和索引:
   db.execSQL("create table if not exists t1(a,b)");        
   db.execSQL("create index if not exists ia on t1(a,b)");
插入10萬條數據,分別對表進行如下操作:
select * from t1 where a='90012'
插入:insert into t1(a,b) values('10008','name1.6982235534984673')
更新:update t1 set b='name1.999999' where a = '887'

刪除:delete from t1 where a = '1010'

數據如下(5次不同的操作取平均值):
操作   無索引    有索引
查詢   170ms  5ms
插入   65ms   75ms
更新   240ms  52ms
刪除   234ms  78ms

        可以看到顯著提升了查詢的速度,稍稍減慢了插入速度,還稍稍提升了更新數據和刪除數據的速度。如果把更新和刪除中的where子句中的列換成b,速度就和沒有索引一樣了,因為索引失效。所以索引能大幅度提升查詢速度,對於刪除和更新操作,如果where子句中的列使用了索引,即使需要重新build索引,有可能速度還是比不使用索引要快的。對與插入操作,索引顯然是個負擔。同時,索引讓db的大小增加了2倍多。

       還有個要吐槽的是,android中的rawQurey方法,執行完sql語句后返回一個cursor,其實並沒有完成一個查詢操作,我在rawquery之前和之后計算查詢時間,永遠是1ms...這讓我無比苦悶。看了下源碼,在對cursor調用moveToNext這些移動游標方法時,都會最終先調用getCount方法,而getCount方法才會調用native方法調用真正的查詢操作。這種設計顯然更加合理。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM