主鍵的創建方式
create table stud( id int not null unique, name varchar(20) ); mysql> desc stud; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
create table stud2( id int, name varchar(20), primary key(id) ); mysql> desc stud2; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | YES | | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
create table stud3( id int not null unique, name varchar(20) not null unique ); mysql> desc stud3; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(20) | NO | UNI | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
create table stud4( name varchar(20) not null unique, id int not null unique ); mysql> desc stud4; +-------+-------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+-------+ | name | varchar(20) | NO | PRI | NULL | | | id | int(11) | NO | UNI | NULL | | +-------+-------------+------+-----+---------+-------+ 2 rows in set (0.00 sec)
聯合主鍵
create table book2author ( id int not null unique auto_increment, book_id int, author_id int, primary key (book_id,author_id) ); mysql> desc book2author; +-----------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+---------+------+-----+---------+----------------+ | id | int(11) | NO | UNI | NULL | auto_increment | | book_id | int(11) | NO | PRI | NULL | | | author_id | int(11) | NO | PRI | NULL | | +-----------+---------+------+-----+---------+----------------+ 3 rows in set (0.00 sec)
使用insert插入值,效果:
mysql> select * from book2author;
+----+---------+-----------+
| id | book_id | author_id |
+----+---------+-----------+
| 1 | 1 | 1 |
| 2 | 2 | 2 |
| 3 | 3 | 3 |
| 4 | 1 | 2 |
| 5 | 1 | 3 |
+----+---------+-----------+
5 rows in set (0.00 sec)
可以理解為:ID號為1的書由ID號為1,2,3的三個作者共同創作完成。
數據庫存儲引擎
什么是存儲引擎
mysql中建立的庫===>文件夾
庫中建立的表===>文件
現實生活中我們用來存儲數據的文件應該有不同的類型:比如存文本用txt類型,存表格用excel,存圖片用png等
數據庫中的表也應該有不同的類型,表的類型不同,會對應mysql不同的存取機制,表類型又稱為存儲引擎。
存儲引擎說白了就是如何存儲數據、如何為存儲的數據建立索引和如何更新、查詢數據等技術的實現方
法。因為在關系數據庫中數據的存儲是以表的形式存儲的,所以存儲引擎也可以稱為表類型(即存儲和
操作此表的類型)
mysql支持的存儲引擎
MySQL常用的存儲引擎
MyISAM存儲引擎
由於該存儲引擎不支持事務、也不支持外鍵,所以訪問速度較快。因此當對事務完整性沒有要求並以訪問為主的應用適合使用該存儲引擎。
InnoDB存儲引擎(主要使用)
由於該存儲引擎在事務上具有優勢,即支持具有提交、回滾及崩潰恢復能力等事務特性,所以比MyISAM存儲引擎占用更多的磁盤空間。因此當需要頻繁的更新、刪除操作,同時還對事務的完整性要求較高,需要實現並發控制,建議選擇。
MEMORY
MEMORY存儲引擎存儲數據的位置是內存,因此訪問速度最快,但是安全上沒有保障。適合於需要快速的訪問或臨時表。
BLACKHOLE
黑洞存儲引擎,可以應用於主備復制中的分發主庫。
使用存儲引擎
方法1:建表時指定
MariaDB [db1]> create table innodb_t1(id int,name char)engine=innodb; MariaDB [db1]> create table innodb_t2(id int)engine=innodb; MariaDB [db1]> show create table innodb_t1; MariaDB [db1]> show create table innodb_t2;
方法2:在配置文件中指定默認的存儲引擎
/etc/my.cnf [mysqld] default-storage-engine=INNODB innodb_file_per_table=1
查看
[root@egon db1]# cd /var/lib/mysql/db1/ [root@egon db1]# ls db.opt innodb_t1.frm innodb_t1.ibd innodb_t2.frm innodb_t2.ibd
練習
創建四個表,分別使用innodb,myisam,memory,blackhole存儲引擎,進行插入數據測試 MariaDB [db1]> create table t1(id int)engine=innodb; MariaDB [db1]> create table t2(id int)engine=myisam; MariaDB [db1]> create table t3(id int)engine=memory; MariaDB [db1]> create table t4(id int)engine=blackhole; MariaDB [db1]> quit [root@egon db1]# ls /var/lib/mysql/db1/ #發現后兩種存儲引擎只有表結構,無數據 db.opt t1.frm t1.ibd t2.MYD t2.MYI t2.frm t3.frm t4.frm #memory,在重啟mysql或者重啟機器后,表內數據清空 #blackhole,往表內插入任何數據,都相當於丟入黑洞,表內永遠不存記錄
存儲過程
存儲過程是一個SQL語句集合,當主動去調用存儲過程時,其中內部的SQL語句會按照邏輯執行。
創建存儲過程
-- 創建存儲過程 delimiter // create procedure p1() BEGIN select * from t1; END// delimiter ; -- 執行存儲過程 call p1()
對於存儲過程,可以接收參數,其參數有三類:
- in 僅用於傳入參數用
- out 僅用於返回值用
- inout 既可以傳入又可以當作返回值
有參數的存儲過程:
-- 創建存儲過程 delimiter \\ create procedure p1( in i1 int, in i2 int, inout i3 int, out r1 int ) BEGIN DECLARE temp1 int; DECLARE temp2 int default 0; set temp1 = 1; set r1 = i1 + i2 + temp1 + temp2; set i3 = i3 + 100; end\\ delimiter ; -- 執行存儲過程 set @t1 =4; set @t2 = 0; CALL p1 (1, 2 ,@t1, @t2); SELECT @t1,@t2;
結果集:
delimiter // create procedure p1() begin select * from v1; end // delimiter ;
結果集+out:
delimiter // create procedure p2( in n1 int, inout n3 int, out n2 int, ) begin declare temp1 int ; declare temp2 int default 0; select * from v1; set n2 = n1 + 100; set n3 = n3 + n1 + 100; end // delimiter ;
事務:
delimiter \\ create PROCEDURE p1( OUT p_return_code tinyint ) BEGIN DECLARE exit handler for sqlexception BEGIN -- ERROR set p_return_code = 1; rollback; END; DECLARE exit handler for sqlwarning BEGIN -- WARNING set p_return_code = 2; rollback; END; START TRANSACTION; DELETE from tb1; insert into tb2(name)values('seven'); COMMIT; -- SUCCESS set p_return_code = 0; END\\ delimiter ;
游標:
delimiter // create procedure p3() begin declare ssid int; -- 自定義變量1 declare ssname varchar(50); -- 自定義變量2 DECLARE done INT DEFAULT FALSE; DECLARE my_cursor CURSOR FOR select sid,sname from student; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; open my_cursor; xxoo: LOOP fetch my_cursor into ssid,ssname; if done then leave xxoo; END IF; insert into teacher(tname) values(ssname); end loop xxoo; close my_cursor; end // delimter ;
動態執行sql:
delimiter \\ CREATE PROCEDURE p4 ( in nid int ) BEGIN PREPARE prod FROM 'select * from student where sid > ?'; EXECUTE prod USING @nid; DEALLOCATE prepare prod; END\\ delimiter ;
刪除存儲過程
drop procedure proc_name;
執行存儲過程
-- 無參數 call proc_name() -- 有參數,全in call proc_name(1,2) -- 有參數,有in,out,inout set @t1=0; set @t2=3; call proc_name(1,2,@t1,@t2)
索引
索引簡介
索引在MySQL中也叫做“鍵”,是存儲引擎用於快速找到記錄的一種數據結構。索引對於良好的性能非常關鍵,尤其是當表中的數據量越來越大時,索引對於性能的影響愈發重要。
索引優化應該是對查詢性能優化最有效的手段了。
索引能夠輕易將查詢性能提高好幾個數量級。
索引相當於字典的音序表,如果要查某個字,如果不使用音序表,則需要從幾百頁中逐頁去查。
索引特點:創建與維護索引會消耗很多時間與磁盤空間,但查詢速度大大提高!
索引語法
創建索引
--創建表時 --語法: CREATE TABLE 表名 ( 字段名1 數據類型 [完整性約束條件…], 字段名2 數據類型 [完整性約束條件…], [UNIQUE] INDEX | KEY [索引名] (字段名[(長度)] [ASC |DESC]) ); -------------------------------- --創建普通索引示例: CREATE TABLE emp1 ( id INT, name VARCHAR(30) , resume VARCHAR(50), INDEX index_emp_name (name) --KEY index_dept_name (dept_name) ); --創建唯一索引示例: CREATE TABLE emp2 ( id INT, name VARCHAR(30) , bank_num CHAR(18) UNIQUE , resume VARCHAR(50), UNIQUE INDEX index_emp_name (name) ); --創建全文索引示例: CREATE TABLE emp3 ( id INT, name VARCHAR(30) , resume VARCHAR(50), FULLTEXT INDEX index_resume (resume) ); --創建多列索引示例: CREATE TABLE emp4 ( id INT, name VARCHAR(30) , resume VARCHAR(50), INDEX index_name_resume (name,resume) ); ---------------------------------
添加和刪除索引
---添加索引 ---CREATE在已存在的表上創建索引 CREATE [UNIQUE] INDEX 索引名 ON 表名 (字段名[(長度)] [ASC |DESC]) ; ---ALTER TABLE在已存在的表上創建索引 ALTER TABLE 表名 ADD [UNIQUE] INDEX 索引名 (字段名[(長度)] [ASC |DESC]) ; CREATE INDEX index_emp_name on emp1(name); ALTER TABLE emp2 ADD UNIQUE INDEX index_bank_num(band_num); -- 刪除索引 語法:DROP INDEX 索引名 on 表名 DROP INDEX index_emp_name on emp1; DROP INDEX bank_num on emp2;
索引測試實驗
--創建表 create table Indexdb.t1(id int,name varchar(20)); --存儲過程 delimiter $$ create procedure autoinsert() BEGIN declare i int default 1; while(i<500000)do insert into Indexdb.t1 values(i,'yuan'); set i=i+1; end while; END$$ delimiter ; --調用函數 call autoinsert(); -- 花費時間比較: -- 創建索引前 select * from Indexdb.t1 where id=300000;--0.32s -- 添加索引 create index index_id on Indexdb.t1(id); -- 創建索引后 select * from Indexdb.t1 where id=300000;--0.00s
pymsql
pymsql是Python中操作MySQL的模塊,其使用方法和MySQLdb幾乎相同。
一、下載安裝:
pip3 install pymysql
二、使用
1、執行SQL
import pymysql # 創建連接 conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') # 創建游標 cursor = conn.cursor() # 執行SQL,並返回收影響行數 effect_row = cursor.execute("update hosts set host = '1.1.1.2'") # 執行SQL,並返回受影響行數 #effect_row = cursor.execute("update hosts set host = '1.1.1.2' where nid > %s", (1,)) # 執行SQL,並返回受影響行數 #effect_row = cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)]) # 提交,不然無法保存新建或者修改的數據 conn.commit() # 關閉游標 cursor.close() # 關閉連接 conn.close()
2、獲取新創建數據自增ID
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') cursor = conn.cursor() cursor.executemany("insert into hosts(host,color_id)values(%s,%s)", [("1.1.1.11",1),("1.1.1.11",2)]) conn.commit() cursor.close() conn.close() # 獲取最新自增ID new_id = cursor.lastrowid
3、獲取查詢數據
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') cursor = conn.cursor() cursor.execute("select * from hosts") # 獲取第一行數據 row_1 = cursor.fetchone() # 獲取前n行數據 # row_2 = cursor.fetchmany(3) # 獲取所有數據 # row_3 = cursor.fetchall() conn.commit() cursor.close() conn.close()
注:在fetch數據時按照順序進行,可以使用cursor.scroll(num,mode)來移動游標位置,如:
- cursor.scroll(1,mode='relative') # 相對當前位置移動
- cursor.scroll(2,mode='absolute') # 相對絕對位置移動
4、fetch數據類型
關於默認獲取的數據是元祖類型,如果想要或者字典類型的數據,即:
import pymysql conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1') # 游標設置為字典類型 cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) r = cursor.execute("call p1()") result = cursor.fetchone() conn.commit() cursor.close() conn.close()