1.索引
爲什麼要有索引?
通常的應用系統,讀寫比例在10:1左右,並且插入操做和通常的更新操做不多出現性能問題,
在生產環境中,咱們遇到最多的,也是最容易出問題的,仍是一些複雜的查詢操做,
所以對查詢語句的優化顯然是重中之重。提及加速查詢,就不得不提到索引了。
彙集索引
葉子節點整個行中的額數據
輔助索引
葉子節點存儲的是索引字段 和主鍵值
覆蓋索引
回表
聯合索引
正確使用索引
1.區分度高字段
2.索引的字段數據量應該儘量小
3.優先使用匯集索引
4.聯合索引 建立時 把區分度高放左邊
查詢時 儘量使用最左邊的索引
索引越多越好?
索引可以提高效率
同時下降了寫入速度
增長額外的磁盤佔用
2.元類
用於建立類的類 叫元類 默認元類都是type
主要控制類的建立__init__ 類的實例化__call__
3.單例
一個類只有一個實例
何時用,你們公用一個打印機,沒有必要每一個人建立新的打印機對象 共用一個對象便可
須要排序操做的字段(order_by)
須要比較操做的字段(> < >= <=)
須要過濾操做的字段( filter exclude)python
常常更新和刪除 的字段不該該被索引mysql
主鍵一定是索引sql
外鍵 默認是索引 (能夠不配置)數據庫
屬性中定義
meta中定義django
from django.db import models from apis.models import App # Create your models here. class User(models.Model): # open_id open_id = models.CharField(max_length=64, unique=True) # 暱稱 nickname = models.CharField(max_length=256, db_index=True) # 關注的城市 focus_cities = models.TextField(default='[]') # 關注的星座 focus_constellations = models.TextField(default='[]') # 關注的股票 focus_stocks = models.TextField(default='[]') # 菜單app menu = models.ManyToManyField(App) class Meta: indexes = [ # models.Index(fields=['nickname']) models.Index(fields=['open_id', 'nickname']) ] def __str__(self): return self.nickname def __repr__(self): return self.nickname
===============================索引01 爲何要用索引 由於項目運行中,查詢操做很是頻繁,爲了提升用戶體驗,要提升查詢的速度, 如何提升就靠索引(大多數性能問題都是慢查詢 提到加速查,就必須用到索引) 做用: - 約束 - 加速查找02 什麼是索引 搜索引導, 因此是一種單獨的,物理的 有序的 存儲結構,用於加速查詢 例如: 字典 書的目錄 車票上的車箱號 索引的本質原理就是經過不斷地縮小查詢範圍,來下降io次數從而提高查詢性能 強調:一旦爲表建立了索引,之後的查詢都會先查索引,再根據索引定位的結果去找數據本質都是:經過不斷地縮小想要獲取數據的範圍來篩選出最終想要的結果,同時把隨機的事件變成順序的事件, 也就是說,有了這種索引機制,咱們能夠老是用同一種查找方式來鎖定數據。03 索引的影響 1.加速查詢 2.下降寫入(增長 刪除 修改)速度 3.會額外佔用磁盤空間4.索引的分類 1.彙集索引 就是主鍵索引 (primary key ) - 主鍵索引:加速查找 + 不能爲空 + 不能重複 行中的完整記錄存在彙集索引的葉子節點上 2.輔助索引 (unique,index) - 普通索引:加速查找 - 惟一索引:加速查找 + 不能重複 葉子節點 存儲索引字段的值 還有 主鍵的值 使用輔助索引時 會產生兩種現象 1.回表 要查的數據就不在輔助索引中 須要到彙集索引中查找 2.覆蓋索引 要查的數據就在輔助索引中 - create index 索引名稱 on 表名(列名,) - drop index 索引名稱 on 表名 - create unique index 索引名稱 on 表名(列名) - drop unique index 索引名稱 on 表名 3 聯合索引(多列): - 聯合主鍵索引 - 聯合惟一索引 - 聯合普通索引 爲是什麼使用它 下降資源的佔用 , 下降增刪改的時間 會比單個字段的索引快 創建聯合索引時 應該把區分度高放最左邊 區分度低的依次往右放 按照區分度的高低 從左往右 依次排列 查詢中 應該優先使用左邊的索引 使用and時 無所謂書寫順序 會自動找區分度最高的 注意聯合索引在查詢時 若是壓根沒用到最左側索引 不能加速查詢 組合索引(最左前綴匹配): - create unique index 索引名稱 on 表名(列名,列名) - drop unique index 索引名稱 on 表名 - create index ix_name_email on userinfo3(name,email,) - 最左前綴匹配 select * from userinfo3 where name='alex'; select * from userinfo3 where name='alex' and email='asdf'; select * from userinfo3 where email='alex@qq.com'; 組合索引效率 > 索引合併 組合索引 - (name,email,) select * from userinfo3 where name='alex' and email='asdf'; select * from userinfo3 where name='alex'; 索引合併: - name - email select * from userinfo3 where name='alex' and email='asdf'; select * from userinfo3 where name='alex'; select * from userinfo3 where email='alex'; 名詞: 覆蓋索引: - 在索引文件中直接獲取數據 索引合併: - 把多個單列索引合併使用索引的正確使用姿式 命中索引 ,條件中有索引字段匹配上 1.不管索引如何設計 沒法下降範圍查詢的查詢速度 select count(*) from usr where id > 1; 即便命中索引也沒法提升效率 2.索引不該該加在值重複度很高的字段上 應該加在重複度低的字段 3. 使用and時 當 條件中出現多個索引命中時 會自定找一個區分度最高的索引來使用 4.使用or的時候 若是兩邊都有索引 會使用索引,可是注意 or兩邊都要執行 順序依然從左往右 只有一邊有索引會不會使用索引? 不會使用 沒法加速查詢 5.優化查詢 不只僅要加索引,sql語句也須要優化 使其能命中索引 你的條件中應該使用區別度高的索引 正常開發時 優先使用匯集索引 再次 使用聯合索引 若是你的條件不包含最左側索引 不能加速查詢 這時候就應該使用單個字段索引 建立索引: create index 索引名稱 on usr(索引字段);索引未命中 詳見49-2並非說咱們建立了索引就必定會加快查詢速度,若想利用索引達到預想的提升查詢速度的效果,咱們在添加索引時,必須遵循如下問題1 範圍問題,或者說條件不明確,條件中出現這些符號或關鍵字: >、>=、<、<=、!= 、between...and...、like、 大於號、小於號 不等於!= between ...and... like2 儘可能選擇區分度高的列做爲索引,區分度的公式是count(distinct col)/count(*), 表示字段不重複的比例,比例越大咱們掃描的記錄數越少,惟一鍵的區分度是1, 而一些狀態、性別字段可能在大數據面前區分度就是0,那可能有人會問, 這個比例有什麼經驗值嗎?使用場景不一樣,這個值也很難肯定, 通常須要join的字段咱們都要求是0.1以上,即平均1條掃描10條記錄3 =和in能夠亂序,好比a = 1 and b = 2 and c = 3 創建(a,b,c)索引能夠任意順序, mysql的查詢優化器會幫你優化成索引能夠識別的形式4 索引列不能參與計算,保持列「乾淨」,好比from_unixtime(create_time) = ’2014-05-29’就不能使用到索引, 緣由很簡單,b+樹中存的都是數據表中的字段值,但進行檢索時,須要把全部元素都應用函數才能比較, 顯然成本太大。因此語句應該寫成create_time = unix_timestamp(’2014-05-29’)5 and/or6 最左前綴匹配原則(詳見第八小節),很是重要的原則,對於組合索引mysql會一直 向右匹配直到遇到範圍查詢(>、<、between、like)就中止匹配(指的是範圍大了,有索引速度也慢), 好比a = 1 and b = 2 and c > 3 and d = 4 若是創建(a,b,c,d)順序的索引, d是用不到索引的,若是創建(a,b,d,c)的索引則均可以用到,a,b,d的順序能夠任意調整。7 其餘狀況總結 #1. 必定是爲搜索條件的字段建立索引,好比select * from s1 where id = 333;就須要爲id加上索引 #2. 在表中已經有大量數據的狀況下,建索引會很慢,且佔用硬盤空間,建完後查詢速度加快 好比create index idx on s1(id);會掃描表中全部的數據, 而後以id爲數據項,建立索引結構,存放於硬盤的表中。建完之後,再查詢就會很快了。 #3. 須要注意的是:innodb表的索引會存放於s1.ibd文件中,而myisam表的索引則會有單獨的索引文件table1.MYI MySAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。 而在innodb中,表數據文件自己就是按照B+Tree(BTree即Balance True)組織的一個索引結構, 這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,所以innodb表數據文件自己就是主索引。 由於inndob的數據文件要按照主鍵彙集,因此innodb要求表必需要有主鍵(Myisam能夠沒有), 若是沒有顯式定義,則mysql系統會自動選擇一個能夠惟一標識數據記錄的列做爲主鍵, 若是不存在這種列,則mysql會自動爲innodb表生成一個隱含字段做爲主鍵,這字段的長度爲6個字節,類型爲長整型.-----wusir2. 頻繁查找的列建立索引 - 建立索引 - 命中索引 ***** - like '%xx' select * from tb1 where email like '%cn'; - 使用函數 select * from tb1 where reverse(email) = 'wupeiqi'; - or select * from tb1 where nid = 1 or name = 'seven@live.com'; 特別的:當or條件中有未創建索引的列才失效,如下會走索引 select * from tb1 where nid = 1 or name = 'seven'; select * from tb1 where nid = 1 or name = 'seven@live.com' and email = 'alex' - 類型不一致 若是列是字符串類型,傳入條件是必須用引號引發來,否則... select * from tb1 where email = 999; - != select * from tb1 where email != 'alex' 特別的:若是是主鍵,則仍是會走索引 select * from tb1 where nid != 123 - > select * from tb1 where email > 'alex' 特別的:若是是主鍵或索引是整數類型,則仍是會走索引 select * from tb1 where nid > 123 select * from tb1 where num > 123 - order by select name from tb1 order by email desc; 當根據索引排序時候,選擇的映射若是不是索引,則不走索引 特別的:若是對主鍵排序,則仍是走索引: select * from tb1 order by nid desc; - 組合索引最左前綴 若是組合索引爲:(name,email) name and email -- 使用索引 name -- 使用索引 email -- 不使用索引3. 查詢優化神器-explain 關於explain命令相信你們並不陌生,具體用法和字段含義能夠參考官網explain-output, 這裏須要強調rows是核心指標,絕大部分rows小的語句執行必定很快 (有例外,下面會講到)。因此優化語句基本上都是在優化rows。 執行計劃:讓mysql預估執行操做(通常正確) all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const id,email 慢: select * from userinfo3 where name='alex' explain select * from userinfo3 where name='alex' type: ALL(全表掃描) select * from userinfo3 limit 1; 快: select * from userinfo3 where email='alex' type: const(走索引)4. DBA工做 慢查詢優化的基本步驟 0.先運行看看是否真的很慢,注意設置SQL_NO_CACHE 1.where條件單表查,鎖定最小返回記錄表。這句話的意思是把查詢語句的where都應用到表中返回的記錄數最小的表開始查起,單表每一個字段分別查詢,看哪一個字段的區分度最高 2.explain查看執行計劃,是否與1預期一致(從鎖定記錄較少的表開始查詢) 3.order by limit 形式的sql語句讓排序的表優先查 4.瞭解業務方使用場景 5.加索引時參照建索引的幾大原則 6.觀察結果,不符合預期繼續從0分析 慢日誌 - 執行時間 > 10 - 未命中索引 - 日誌文件路徑 配置: - 內存 show variables like '%query%' set global 變量名 = 值 - 配置文件 mysqld --defaults-file='E:\wupeiqi\mysql-5.7.16-winx64\mysql-5.7.16-winx64\my-default.ini' my.conf內容: slow_query_log = ON slow_query_log_file = D:/.... 注意:修改配置文件以後,須要重啓服務5. ******分頁******* a. select * from userinfo3 limit 20,10; b. - 不讓看 - 索引表中掃: select * from userinfo3 where id in(select id from userinfo3 limit 200000,10) - 方案: 記錄當前頁最大或最小ID 1. 頁面只有上一頁,下一頁 # max_id # min_id 下一頁: select * from userinfo3 where id > max_id limit 10; 上一頁: select * from userinfo3 where id < min_id order by id desc limit 10; 2. 上一頁 192 193 [196] 197 198 199 下一頁 select * from userinfo3 where id in ( select id from (select id from userinfo3 where id > max_id limit 30) as N order by N.id desc limit 10 ) c. *****閆龍*****: id不連續,因此沒法直接使用id範圍進行查找1. ORM框架:SQLAlchemy SQLAlchemy是Python編程語言下的一款ORM框架,該框架創建在數據庫API之上,使用關係對象映射進行數據庫操做, 簡言之即是:將對象轉換成SQL,而後使用數據API執行SQL並獲取執行結果。 - 做用: 1. 提供簡單的規則 2. 自動轉換成SQL語句 - DB first: 手動建立數據庫以及表 -> ORM框架 -> 自動生成類 - code first: 手動建立類、和數據庫 -> ORM框架 -> 以及表 a. 功能 - 建立數據庫表 - 鏈接數據庫(非SQLAlchemy,pymyql,mysqldb,....) - 類轉換SQL語句 - 操做數據行 增 刪 改 查 - 便利的功能