1)三范式
一范式:原子性,屬性不可分;
二范式:無部分依賴,
例:(學號, 課程名稱) → (姓名, 年齡, 成績, 學分),存在部分依賴 (學號) → (姓名, 年齡)
拆分;(學號, 姓名, 年齡),(課程名稱, 學分), (學號, 課程名稱, 成績),
三范式:無傳遞依賴,
例:(學號)→(姓名,年齡,性別,系別,系辦地址、系辦電話)
傳遞依賴:
(學號)→ (系別)→(系辦地點,系辦電話)
再拆分。。。
2)逆范式:
相片表(相片id,名稱,點擊次數,所屬相冊id,上傳時間)
相冊表(相冊id,名稱,時間)
若有相冊點擊次數的需求,並且頻繁,則需要在相冊表添加“點擊次數”冗余字段。
添加冗余字段的規范:
一對多的情況
冗余的字段應該盡量在“一”的一方。
若在相片表放冗余字段“相冊名稱”,雖然反問相冊名稱方便了。但造成極大的空間浪費,並且極大的提高了修改成本。
3)反外鍵
有外鍵關系,但不加入外鍵約束。
外鍵的缺點:略
1)五類sql語句
ddl
dml
select
dtl事務控制語句 commit\rollback\savepoint
dcl數據控制語句 grant\revork
sql優化的核心是select,你知道為什麼的。
2)show status命令
查看數據庫當前狀態,比較有用的幾個狀態包括:
a) show status like 'Com%' <=> show session status like 'Com%' //當前控制台的情況
b) show global status 'Com%'; //數據庫從啟動到現在的狀態
c) show status like 'Connections' 顯示鏈接數據庫的次數
d) show status like 'Uptime' 服務器工作時間(秒)
e) show status like 'Slow_queries' 慢查詢的次數(默認是10秒)
3)這裡我們優化的重點是慢查詢。
a)show variables like 'long_query_time'
默認為10秒,要求高一點,我們設為1秒。
set long_query_time = 1
搞個海量表玩一下,測試性能。
Show status like ‘slow_queres’
發現當前慢查詢此時是0。
b)可以自定義函數 + 存儲過程,創建一個海量表
自定義函數,產生一個隨機字符串:
Delimiter $$
Drop function if exists rand_string;
Create function rand_string(n INT)
Returns varchar(255)
Begin
Declare chars_str varchar(100) default
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
Declare return_str varchar(255) default '';
Declare i int default 0;
While i < n do
Set return_str = concat(return_str,substring(chars_str,floor(1+rand()*52),1));
Set i = i + 1;
End while;
Return return_str;
End $$
Delimiter ; $$
存儲過程:
Drop table if exists emp;
Create table emp(
Id int primary key,
name varchar(255),
descp varchar(255),
gene varchar(16)
);
Delimiter $$
Drop PROCEDURE if exists proc_insertemp;
CREATE PROCEDURE proc_insertemp(in start int(10), in max_num int(10) )
Begin
Declare i int default 0;
Set autocommit = 0;
Repeat
Set i = i + 1;
Insert into emp values ((start+i), rand_string(6), 'salesman','man');
Until i = max_num
End repeat;
Commit;
End $$
Delimiter ; $$
使用存儲過程
Call proc_insertemp(10000, 20000);
c)mysql支持把慢查詢語句記錄到日志中,供程序員分析。
默認情況是不啟用的。
進入到mysql安裝目錄,啟動--slow-query-log
d)索引
show indexes from tb
主鍵索引 alter table tb add primary key (keyname);
唯一索引 unique 即該列具有唯一性,同時又是索引。
普通索引 index
全文索引fullindex(僅mylsam支持)
復合索引(多列在一起,聯合索引)從左到右順序。
中文索引
sphinx + 中文分詞coreseek
4)explain指令
explain select * from tb where id = 2000
select_type: simple
table: tb
type: all //檢索類型
possible_keys: primary //可能用到的索引
key: primary //實際用到的索引
key_len:
ref:
rows: 1 //從多少條記錄中取出,因為有索引,所以是1
extra: using where //using temporary using filesort等
查詢全表的邏輯在真實的項目裡是沒有道理的,必然存在分頁的邏輯。分頁必然有索引
5)索引添加場景
a) 較頻繁的作為查詢條件的字段應該創建索引
b)唯一性太差的字段不適合單獨創建索引,即使頻繁作為查詢條件
select * from tb where sex = 'n男';
c)更新非常頻繁的字段,不適合添加索引。
6)不會用到索引的情況
a)like%放前邊不會用到索引,放在中間和後面才能用到;
b)對於復合索引,只要查詢條件使用了最左邊的列,索引一般就會被使用。而如果只使用右邊的列,則不會被使用。
c)如果mysql估計使用全表掃描比使用索引快,則不使用索引。
7)使用索引的注意事項
a)如何檢測索引是否有效
show status like 'Handler_read%'
b)handler_read_key值越高,表示使用索引查詢到的次數越多
c)handler_read_key值越高,說明查詢效率低
8)常用技巧
對於大批量插入數據
a) myisam先關閉keys,導入完畢再開啟;
alter table table_name disable keys;
loading data;
alter table table_name enable keys;
b) 對於innodb 數據排序、關閉唯一性校驗(不至於每插入一條校驗一條)、關閉自動提交
Set unique_check = 0;
Set autocommit = 0;
group by 會默認排序,可以通過order by null禁用排序;
子查詢會生成臨時表,可以用join代替;
在精度要求高的應用中,建議使用定點數來存儲數值decimal,而不要使用浮點數,以保證結果的准確性。如 10000000.32萬,插入float(10,2) 型是10000000.31。
日期類型要根據實際需要選擇能滿足應用的最小存儲的早期類型。用時間戳的話,很方便按范圍搜索。比如查前三天的記錄。但注意int型時間戳,只能表示到2038年。
圖片的存儲采用路徑存儲。甚至專門的圖片服務器(圖床)
9)MylSAM和Innodb的區別
前者有存儲緩存,需要手動回收過期數據。MyISAM創建一張表,對應三個文件,如果Innodb則只有一個文件 *.frm
對於MyISAM數據庫,需要定時清理。
optimize table 表名。
show engines;字段 Support為:Default表示默認存儲引擎 。默認為Innodb。
把緩存設置大一些:
innodb_additional_mem_pool_size = 64M
innodb_buff_pool_size = 1G
key_buff_size
內存超過4G,用64位系統
1)表的分割,水平分割(分庫分表)、垂直分割(將表的粒度化小)
2)讀寫分離:緩解查詢壓力
a)判斷請求的sql語句,判斷dml語句,則由master處理,slave定時同步master數據。
b)判斷若讀的sql,則由lvs從slave讀取即可。
1、選取最適用的字段屬性
MySQL 可以很好的支持大數據量的存取,但是一般說來,數據庫中的表越小,在它上面執行的查詢也就會越快。因此,在創建表的時候,為了獲得更好的性能,我們可以將表中字段的寬度設得盡可能小。例如,在定義郵政編碼這個字段時,如果將其設置為CHAR(255),顯然給數據庫增加了不必要的空間,甚至使用VARCHAR這種類型也是多余的,因為CHAR(6)就可以很好的完成任務了。同樣的,如果可以的話,我們應該使用MEDIUMINT而不是BIGIN來定義整型字段。
另外一個提高效率的方法是在可能的情況下,應該盡量把字段設置為NOT NULL,這樣在將來執行查詢的時候,數據庫不用去比較NULL值。
對於某些文本字段,例如“省份”或者“性別”,我們可以將它們定義為ENUM類型。因為在MySQL中,ENUM類型被當作數值型數據來處理,而數值型數據被處理起來的速度要比文本類型快得多。這樣,我們又可以提高數據庫的性能。
2、使用連接(JOIN)來代替子查詢(Sub-Queries)
MySQL 從4.1開始支持SQL的子查詢。這個技術可以使用SELECT語句來創建一個單列的查詢結果,然後把這個結果作為過濾條件用在另一個查詢中。例如,我們要將客戶基本信息表中沒有任何訂單的客戶刪除掉,就可以利用子查詢先從銷售信息表中將所有發出訂單的客戶ID取出來,然後將結果傳遞給主查詢,如下所示:
DELETE FROM customerinfo
WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )
使用子查詢可以一次性的完成很多邏輯上需要多個步驟才能完成的SQL操作,同時也可以避免事務或者表鎖死,並且寫起來也很容易。但是,有些情況下,子查詢可以被更有效率的連接(JOIN).. 替代。例如,假設我們要將所有沒有訂單記錄的用戶取出來,可以用下面這個查詢完成:
SELECT * FROM customerinfo
WHERE CustomerID NOT in (SELECT CustomerID FROM salesinfo )
如果使用連接(JOIN).. 來完成這個查詢工作,速度將會快很多。尤其是當salesinfo表中對CustomerID建有索引的話,性能將會更好,查詢如下:
SELECT * FROM customerinfo
LEFT JOIN salesinfoON customerinfo.CustomerID=salesinfo.
CustomerID
WHERE salesinfo.CustomerID IS NULL
連接(JOIN).. 之所以更有效率一些,是因為 MySQL不需要在內存中創建臨時表來完成這個邏輯上的需要兩個步驟的查詢工作。
3、使用聯合(UNION)來代替手動創建的臨時表
MySQL 從 4.0 的版本開始支持 UNION 查詢,它可以把需要使用臨時表的兩條或更多的 SELECT 查詢合並的一個查詢中。在客戶端的查詢會話結束的時候,臨時表會被自動刪除,從而保證數據庫整齊、高效。使用 UNION 來創建查詢的時候,我們只需要用 UNION作為關鍵字把多個 SELECT 語句連接起來就可以了,要注意的是所有 SELECT 語句中的字段數目要想同。下面的例子就演示了一個使用 UNION的查詢。
SELECT Name, Phone FROM client
UNION
SELECT Name, BirthDate FROM author......余下全文>>
不要為了優化而優化,這意思是針對問題再進行優化。看你數據庫哪方面性能差,是bufferpool小,io大,還是排序溢出等等。不要同時優化幾個參數,一次一個。不同數據庫大致原理差不多