python — 索引與pymysql模塊

1. 索引

1.1 索引原理

1.什麼是索引 ?-- 目錄html

索引就是創建起的一個在存儲表階段就有的一個存儲結構,能在查詢的時候加速。python

2.索引的重要性:mysql

讀寫比例 爲 10:1,全部讀(查詢)的速度就相當重要了。android

3.索引的原理:ios

block 磁盤預讀原理sql

至關於讀文件操做的 :for line in f數據庫

每一個索引塊能夠存4096個字節安全

讀硬盤的io操做的時間很是的長,比CPU執行指令的時間長不少,儘可能的減小IO次數纔是讀寫數據的主要要解決的問題。服務器

1.2 數據庫的存儲方式

1.數據庫的存儲方式:session

  • 1.新的數據結構 —— 樹

    缺點:容易出現數據只在一端,形成讀取慢(io操做次數多)。

  • 2.平衡樹 balance tree - b樹

    缺點:存儲的數據長度大、能存儲的數據條數有限,形成書的高度比較大,讀取效率很低。

  • 3.在b樹的基礎上進行了改良 - b+樹

    • 1.分支節點和根節點都不在存儲實際的數據了,讓分支和根節點能存儲更多的索引的信息,就下降了樹的高度,全部的實際數據都存儲在葉子節點中
    • 2.在葉子節點之間加入了雙向的鏈式結構,方便在查詢中的範圍條件。

4.mysql當中全部的b+樹索引的高度都基本控制在3層:

  • 1.io操做的次數很是穩定
  • 2.有利於經過範圍查詢

5.什麼會影響索引的效率? —— 樹的高度

  • 1.對哪一列建立索引,選擇儘可能短的列作索引
  • 2.對區分度高的列建索引,重複率超過了10%,那麼就不適合建立索引。

1.3 彙集索引和輔助索引

  • 在innodb中 :彙集索引和輔助索引並存的

    彙集索引 - 主鍵 、更快

    • 只有主鍵是彙集索引

    • 數據直接存儲在樹結構的葉子節點

    輔助索引 - 除了主鍵以外全部的索引都是輔助索引 、稍慢

    • 數據不直接存儲在樹中

  • 在myisam中 :只有輔助索引,沒有彙集索引

1.4 索引的種類

1.索引的種類:

  • primary key 主鍵 ,是彙集索引 ,約束的做用:非空 + 惟一

    聯合主鍵

  • unique 自帶索引 ,是輔助索引 ,約束的做用:惟一

    聯合惟一

  • index 是輔助索引,沒有約束做用

    聯合索引

注意:按大項分有三個種類:primary key 、unique 、index

​ 細分有6個種類:primary key 、聯合主鍵 、unique 、聯合惟一 、index 、聯合索引

2.看一下如何建立索引、建立索引以後的變化

create index 索引名字 on 表(字段)

刪除索引 :drop index 索引名 on 表名字;

3.索引是如何發揮做用的?

select * from 表 where id = xxxxx;

  • 以email爲條件查詢:
    • 不添加索引的時候,確定慢
    • 查詢的字段不是索引字段,也慢
  • id做爲條件的時候:
    • 在id字段沒有索引的時候,效率低
    • 在id字段有索引以後,效率高

1.5 索引不生效的緣由

1.索引不生效的緣由:

<1.>要查詢的數據的範圍大

與範圍相關的:

  • 1.< >= <= !=(!=幾乎命中不了索引)

  • 2.between and

    select * from 表 order by age limit 0,5;

    select * from 表 where id between 1000000 and 1000005;

  • 3.like

    • 結果的範圍大 索引不生效
    • 若是 abc% 索引生效,%abc索引就不生效

<2.>若是一列內容的區分度不高,索引也不生效

  • 如:name列

<3.>索引列不能在條件中參與計算

  • select * from s1 where id*10 = 1000000; 索引不生效

<4.>對兩列內容進行條件查詢

  • and :and條件兩端的內容,優先選擇一個有索引的,而且樹形結構更好的,來進行查詢(效率也會更高)。兩個條件都成立才能完成where條件,先完成範圍小的,縮小後面條件的壓力。

    • select * from s1 where id =1000000 and email = 'eva1000000@oldboy';
  • or :帶or條件的,不會進行優化,只是根據條件從左到右依次篩選。

    條件中帶有or的要想命中索引,這些條件中全部的列都是索引列。

    • select * from s1 where id =1000000 or email = 'eva1000000@oldboy';

<5.>聯合索引

建立聯合索引:create index ind_mix on s1(id,name,email);

  • select * from s1 where id =1000000 and email = 'eva1000000@oldboy';   能命中索引
  • 1.在聯合索引中若是使用了or條件索引就不能生效:

    select * from s1 where id =1000000 or email = 'eva1000000@oldboy'; 不能命中索引

  • 2.最左前綴原則 :在聯合索引中,條件必須含有在建立索引的時候的第一個索引列。

    select * from s1 where id =1000000;    能命中索引
    select * from s1 where email = 'eva1000000@oldboy';  不能命中索引
    
    # 聯合索引 (a,b,c,d)
    a,b 、 a,c  、 a  、 a,d  、 a,b,d  、 a,c,d  、 a,b,c,d # 等含有a索引的都能命中索引
    # 不含a索引的其餘索引都不能命中。
  • 3.在整個條件中,從開始出現模糊匹配的那一刻,索引就失效了

    select * from s1 where id >1000000 and email = 'eva1000001@oldboy';   不能命中索引
    
    select * from s1 where id =1000000 and email like 'eva%';    能命中引

2.何時用聯合索引?

  • 只對a 、對abc 條件進行索引,而不會對b,對c進行單列的索引的時候。

3.對於單列的索引:

  • 選擇一個區分度高的列創建索引,條件中的列不要參與計算,條件的範圍儘可能小,使用and做爲條件的鏈接符

4.使用or來鏈接多個條件:

  • 在知足上述條件(單列的索引)的基礎上,對or相關的全部列分別建立索引。

1.6 一些索引名詞

1.覆蓋索引

若是咱們使用索引做爲條件查詢,查詢完畢以後,不須要回表查,就是覆蓋索引。

explain select id from s1 where id = 1000000;
explain select count(id) from s1 where id > 1000000;

2.合併索引

對兩個字段分別建立索引,因爲sql的條件讓兩個索引同時生效了,那麼這個時候這兩個索引就成爲了合併索引

3.執行計劃 explain

若是你想在執行sql語句以前就知道sql語句的執行狀況,那麼可使用執行計劃。

# 狀況1:
若是有30000000條數據,使用sql語句查詢須要20s,
explain sql語句   --> 並不會真正的執行sql,而是會給你列出一個執行計劃
# 狀況2:
        20條數據 --> 30000000
            explain sql

4.建議

<1>建表、使用sql語句的時候注意的:

  • char 代替 varchar
  • 連表 代替 子查詢
  • 建立表的時候 :固定長度的字段放在前面

<2> utf8 與 utf8mb4 :

  • utf8 不是能全量顯示中文的編碼,如不少不經常使用的生僻字 和 Emoji 表情(Emoji 是一種特殊的 Unicode 編碼,常見於 ios 和 android 手機上),以及任何新增的 Unicode 字符等等
  • utf8mb4 能全量顯示中文的編碼

之後若是遇到使用 utf8 出現亂碼的狀況,能夠更改成 utf8mb4 進行編碼。

1.7 慢查詢優化的基本步驟

  1. 先運行看看是否真的很慢,注意設置SQL_NO_CACHE

1.where條件單表查,鎖定最小返回記錄表。這句話的意思是把查詢語句的where都應用到表中返回的記錄數最小的表開始查起,單表每一個字段分別查詢,看哪一個字段的區分度最高
2.explain查看執行計劃,是否與第1步預期一致(從鎖定記錄較少的表開始查詢)
3.order by limit 形式的sql語句讓排序的表優先查
4.瞭解業務方使用場景
5.加索引時參照建索引的幾大原則
6.觀察結果,不符合預期繼續從0分析

1.8 慢日誌管理

1.慢日誌

  • 執行時間 > 10
  • 未命中索引
  • 日誌文件路徑

2.配置:

  • 內存

    show variables like '%query%';

    show variables like '%queries%';

    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:/....

    注意:修改配置文件以後,須要重啓服務

3.日誌管理

詳見網址:https://www.cnblogs.com/Eva-J/articles/10126413.html#_label8

2. pymysql模塊

2.1 使用pymysql模塊

python至關因而客戶端

import pymysql
conn = pymysql.connect(host='127.0.0.1', user='root', password="123",database='day40') # python與mysql鏈接
cur = conn.cursor()   # 建立 數據庫操做符:遊標

# 增長數據
cur.execute('insert into employee(emp_name,sex,age,hire_date) '
            'values ("郭凱豐","male",40,20190808)')

# 刪除數據
cur.execute('delete from employee where id = 18')
conn.commit() # 提交
conn.close()

# 查詢數據
import pymysql
conn = pymysql.connect(host='127.0.0.1', user='root', password="123",database='day40')
cur = conn.cursor(pymysql.cursors.DictCursor)   # 想要輸出爲字典格式時加上pymysql.cursors.DictCursor
cur.execute('select * from employee where id > 10')
ret = cur.fetchone()  # 查詢第一條數據
print(ret['emp_name'])
ret = cur.fetchmany(5) # 查詢5條數據
ret = cur.fetchall()  # 查詢全部的數據
print(ret)
conn.close()

2.2 數據備份和事務

1.數據庫的邏輯備份

語法:mysqldump -h 服務器 -u用戶名 -p密碼 數據庫名 > 備份文件.sql

#示例:
#單庫備份
mysqldump -uroot -p123 db1 > db1.sql
mysqldump -uroot -p123 db1 table1 table2 > db1-table1-table2.sql

#多庫備份
mysqldump -uroot -p123 --databases db1 db2 mysql db3 > db1_db2_mysql_db3.sql

#備份全部庫
mysqldump -uroot -p123 --all-databases > all.sql

2.數據恢復

#方法一:
[root@egon backup]# mysql -uroot -p123 < /backup/all.sql

#方法二:
mysql> use db1;
mysql> SET SQL_LOG_BIN=0;   #關閉二進制日誌,只對當前session生效
mysql> source /root/db1.sql

3.事務

begin;  # 開啓事務
select * from emp where id = 1 for update;  # 查詢id值,for update添加行鎖;
update emp set salary=10000 where id = 1; # 完成更新
commit; # 提交事務(解鎖)

注意3個關鍵點:

  • begin
  • commit
  • for update

2.3 sql注入

create table userinfo(
id int primary key auto_increment,
name char(12) unique not null,
password char(18) not null
)

insert into userinfo(name,password) values('alex','alex3714')

# 用戶名和密碼到數據庫裏查詢數據
# 若是能查到數據 說明用戶名和密碼正確
# 若是查不到,說明用戶名和密碼不對
username = input('user >>>')
password = input('passwd >>>')
sql = "select * from userinfo where name = '%s' and password = '%s'"%(username,password)
print(sql)

-- :表示註釋掉--以後的sql語句
select * from userinfo where name = 'alex' ;-- and password = '792164987034';
select * from userinfo where name = 219879 or 1=1 ;-- and password = 792164987034;
select * from userinfo where name = '219879' or 1=1 ;-- and password = '792164987034';

上面的輸入狀況都能查詢到結果,因此存在安全隱患,這種存在安全隱患的狀況就叫 sql注入。

爲了不 sql注入,在用pymysql時,不要再本身去拼接sql語句了,要讓mysql模塊本身去拼接。

import pymysql

conn = pymysql.connect(host = '127.0.0.1',user = 'root',
                       password = '123',database='day41')
cur = conn.cursor()
username = input('user >>>')
password = input('passwd >>>')
sql = "select * from userinfo where name = %s and password = %s"
cur.execute(sql,(username,password))  # 讓mysql模塊去拼接
print(cur.fetchone())
cur.close()
conn.close()
相關文章
相關標籤/搜索