最近在寫項目的時候發現本身的SQL基本功有些薄弱,遂上知乎查詢MYSQL關鍵字,指望獲得某些高贊答案的指點,因而乎發現了html
https://www.zhihu.com/question/34840297/answer/272185020 這位老兄的建議的書單,根據他的建議首先拜讀了《MYSQL必知必會》這本書,總體講的很基礎,頁數也很少一共 253 頁,適合基礎比較薄弱的同窗進行食用。而後按部就班,閱讀更深層次的書籍進行自我提高。這裏記載了本身在閱讀的過程當中記錄的一些關鍵內容,分享給你們。書本 PDF 能夠在上面的知乎連接獲取,或者點擊 http://www.notedeep.com/note/38/page/282 前往老哥的深度筆記進行下載。mysql
SQL語句不區分大小寫,而且在 Windows 環境下,4.1.1版本以後(如今經常使用的都是 5.6/5.7/8.0+),MYSQL表名,字段名也是不區分大小寫的,所以咱們在命名的時候建議使用單個單詞_單個單詞的形式命名,如:mysql_crash_course user_rolesql
這裏附上阿里代碼規範的一條強制要求:數據庫
【強制】表名、字段名必須使用小寫字母或數字,禁止出現數字開頭,禁止兩個下劃線中間只出現數字。數據庫字段名的修改代價很大,由於沒法進行預發佈,因此字段名稱須要慎重考慮。
說明: MySQL 在 Windows 下不區分大小寫,但在 Linux 下默認是區分大小寫。所以,數據庫名、表名、字段名,都不容許出現任何大寫字母,避免節外生枝。服務器
好比項目中有這麼一個需求:多線程
須要分頁查詢綁了某收費標準的房屋,由於是房屋列表查詢,咱們默認相同ID的房屋只出現一次,錯誤的SQL以下:併發
房屋表app
收費標準表less
SELECT DISTINCT h.id, h.num, s.name FROM house h LEFT JOIN standard s ON h.id = s.room_id WHERE s.name = '物業費' OR s.name = '暖氣費';
這條語句並不能返回想要的結果,即每套房屋只出現一次,由於不一樣的收費標準名稱不同,DISTINCT 不能對部分查詢條件去重。能夠看到房號爲1-001的記錄出現了兩次。ide
不過其實按照需求的描述我這裏僅查詢房屋的信息,對於查詢結果來講同一條記錄的房屋信息確定徹底相同,所以 DISTINCT 在個人業務中知足要求。而有其餘業務須要此關鍵字的時候,請你們慎重使用,切記不能部分使用該關鍵字
在對文本性的數據進行排序時,A與a相同嗎?a位於B以前仍是位於Z以後?
在建立字段時能夠指定字符集,通常使用 utf8mb4, 此時能夠選擇相應的排序規則。
在區間查詢時,咱們最關注的不該該是區間內的可否被匹配到,由於這是確定的。而區間的邊界可否被匹配纔是咱們應該注意的知識點,BETWEEN AND 關鍵字匹配區間時,包含左右邊界條件。以下面的 SQL 執行結果以下:
SELECT prod_name, prod_price FROM products p WHERE p.`prod_price` BETWEEN 5.99 AND 10
在經過過濾選擇出不具備特定值的行時,你可能但願返回具備 NULL 值的行。可是,不行。常見的錯誤會發生在is_xxx 字段上,我常常有這個毛病,
對於 is_delete 字段,我認爲爲 null 或者 0 都是未刪除的房屋,因此當我使用
SELECT * FROM house WHERE is_delete = '0';
查詢未刪除的房屋時,我只能查到 id 爲 3 的房屋,這顯然與個人預期是不符的,解決辦法是where後面加 or is_delete is null ,或者給 is_delete 列默認值 0;建議使用後者。
這裏附上阿里代碼手冊的一條強制項目:
【強制】表達是與否概念的字段,必須使用 is_xxx 的方式命名,數據類型是 unsigned tinyint(1 表示是,0 表示否)。說明:任何字段若是爲非負數,必須是 unsigned 。
解釋:tinyint 至關於 Java 中的 byte,取值範圍 -128 ~ 127 ,用來表達是否長度已經足夠,也能夠用來表示人的年齡。而 unsigned 表示無符號的,對於肯定爲非負數的字段,使用 unsigned 能夠將取值範圍擴大一倍。
舉個例子:假如須要列出價格爲10美圓(含)以上且由 1002 或 1003 製造的全部產品。下面的 SELECT 語句使用 AND 和 OR 操做符的組合創建了一個WHERE 子句:
SELECT * FROM products WHERE vend_id = 1002 OR vend_id = 1003 AND prod_price >= 10;
查詢結果以下:
而被我用紅框標註的行很顯然不是咱們須要的行,爲何會這樣呢?緣由在於計算的次序。SQL(像多數語言同樣)在處理 OR 操做符前,優先處理 AND 操做符。當SQL看到上述 WHERE 子句時,它理解爲由供應商 1003 製造的任何價格爲10美圓(含)以上的產品,或者由供應商 1002 製造的任何產品,而無論其價格如何。換句話說,因爲 AND 在計算次序中優先級更高,操做符被錯誤地組合了。解決方法就是加 ();正確的 SQL 以下:
SELECT * FROM products WHERE (vend_id = 1002 OR vend_id = 1003) AND prod_price >= 10;
建議在任什麼時候候使用具備 AND 和 OR 操做符的 WHERE 子句,都應該使用圓括號明確地分組操做符。不要過度依賴默認計算次序,即便它確實是你想要的東西也是如此。使用圓括號沒有什麼壞處,它能消除歧義。
通常不要使用沒有明確給出列的列表的 INSERT 語句。使用列的列表能使SQL代碼繼續發揮做用,即便表結構發生了變化。實際開發中有可能因爲業務的須要,對錶結構進行修改,添加/刪除某一列。這時若是代碼中使用的SQL語句是沒有明確列表的插入語句就會報錯。固然通常咱們使用逆向工程生成的 insertSelective(POJO) 並不存在這個問題,由於它對應生成的 SQL 會爲咱們生成列的列表。
MySQL 沒有撤銷按鈕,所以在使用 UPDATE / DELETE 時必定要加上 WHERE 條件,而且在執行更新/刪除操做以前先進行 SELECT 操做,開啓事務。在執行結束後覈對影響的行數和 SELECT 查詢出來的行數一致後再 COMMIT;
另外,使用 ALTER TABLE 要極爲當心,應該在進行改動前作一個完整的備份(模式和數據的備份)。數據庫表的更改不能撤銷,若是增長了不須要的列,可能不能刪除它們。相似地,若是刪除了不該該刪除的列,可能會丟失該列中的全部數據。
其中視圖不能索引這一點要格外注意,在我開發過程當中遇到過這樣一個視圖:使用 UNION 連結了好幾張表進行查詢,對查詢的結果使用 WHERE 條件再過濾,這裏雖然對於被鏈接的表對於 WHERE 條件後的字段都創建了索引,可是使用 UNION 連結生成視圖的臨時表並不能擁有索引。所以查詢的效率會很慢!因此建議在 UNION 查詢中將 WHERE 條件放在每一個 SELECT 語句中。
首先,MySQL(與全部DBMS同樣)具備特定的硬件建議。在學習和研究MySQL時,使用任何舊的計算機做爲服務器均可以。但
對用於生產的服務器來講,應該堅持遵循這些硬件建議。
通常來講,關鍵的生產DBMS應該運行在本身的專用服務器上。
MySQL是用一系列的默認設置預先配置的,從這些設置開始一般是很好的。但過一段時間後你可能須要調整內存分配、緩衝區大小等。(爲查看當前設置,可以使用 SHOW VARIABLES; 和 SHOWSTATUS; )
MySQL一個多用戶多線程的DBMS,換言之,它常常同時執行多個任務。若是這些任務中的某一個執行緩慢,則全部請求都會執
行緩慢。若是你遇到顯著的性能不良,可以使用 SHOW PROCESSLIST顯示全部活動進程(以及它們的線程ID和執行時間)。你還能夠用KILL 命令終結某個特定的進程(使用這個命令須要做爲管理員登陸)。
老是有不止一種方法編寫同一條 SELECT 語句。應該試驗聯結、並、子查詢等,找出最佳的方法。
使用 EXPLAIN 語句讓MySQL解釋它將如何執行一條 SELECT 語句。
通常來講,存儲過程執行得比一條一條地執行其中的各條MySQL語句快。但存儲過程通常難以調試和擴展,而且沒有移植性,所以阿里代碼規約裏面強制禁止使用存儲過程
應該老是使用正確的數據類型。
決不要檢索比需求還要多的數據。換言之,不要用 SELECT * (除非你真正須要每一個列)。
有的操做(包括 INSERT )支持一個可選的 DELAYED 關鍵字,若是使用它,將把控制當即返回給調用程序,而且一旦有可能就實際執行該操做。
延遲插入,當插入和查詢併發執行時,插入被放入等待隊列中。直至全部查詢執行完畢後執行插入。而且MYSQL會在收到插入請求後直接返回給客戶端狀態信息,既是INSERT語句還在隊列中
在導入數據時,應該關閉自動提交。你可能還想刪除索引(包括FULLTEXT 索引),而後在導入完成後再重建它們。
必須索引數據庫表以改善數據檢索的性能。肯定索引什麼不是一件微不足道的任務,須要分析使用的 SELECT 語句以找出重複的WHERE 和 ORDER BY 子句。若是一個簡單的 WHERE 子句返回結果所花的時間太長,則能夠判定其中使用的列(或幾個列)就是須要索引的對象。
你的 SELECT 語句中有一系列複雜的 OR 條件嗎?經過使用多條SELECT 語句和鏈接它們的 UNION 語句,你能看到極大的性能改進。
索引改善數據檢索的性能,但損害數據插入、刪除和更新的性能。若是你有一些表,它們收集數據且不常常被搜索,則在有必要以前不要索引它們。(索引可根據須要添加和刪除。)
LIKE 很慢。通常來講,最好是使用 FULLTEXT 而不是 LIKE 。可是 MYSQL FULLTEXT 對漢字並不友好,若是須要使用全文索引,建議使用搜索引擎 ES,能夠參考個人另外一篇博客: https://www.cnblogs.com/keatsCoder/p/11341835.html
數據庫是不斷變化的實體。一組優化良好的表一下子後可能就面目全非了。因爲表的使用和內容的更改,理想的優化和配置也會改變。
最重要的規則就是,每條規則在某些條件下都會被打破。
實際開發過程當中,咱們須要根據業務的須要,開啓慢查詢日誌,而後針對慢SQL,不斷地進行 EXPLAIN 與修改SQL和索引,以求達到 ref 級別,至少達到 range 級別。這就須要強大的內功支持而不是每次都經過百度來解決,但願閱讀此篇文章的你和我一塊兒不斷修煉。加油!
因爲數中所附的附件內容(建表語句即數據插入語句)須要外網才能訪問,爲了方便你們使用。這裏我已經下載下來附在了這篇博客裏面。若是不須要這些語句,能夠直接經過網頁右邊的目錄跳躍到下一章進行瀏覽
######################################## # MySQL Crash Course MYSQL必知必會建表語句 # http://www.forta.com/books/0672327120/ # 提供者博客園:後青春期的Keats 複製請註明出處 ######################################## ######################## # Create customers table ######################## CREATE TABLE customers ( cust_id int NOT NULL AUTO_INCREMENT, cust_name char(50) NOT NULL , cust_address char(50) NULL , cust_city char(50) NULL , cust_state char(5) NULL , cust_zip char(10) NULL , cust_country char(50) NULL , cust_contact char(50) NULL , cust_email char(255) NULL , PRIMARY KEY (cust_id) ) ENGINE=InnoDB; ######################### # Create orderitems table ######################### CREATE TABLE orderitems ( order_num int NOT NULL , order_item int NOT NULL , prod_id char(10) NOT NULL , quantity int NOT NULL , item_price decimal(8,2) NOT NULL , PRIMARY KEY (order_num, order_item) ) ENGINE=InnoDB; ##################### # Create orders table ##################### CREATE TABLE orders ( order_num int NOT NULL AUTO_INCREMENT, order_date datetime NOT NULL , cust_id int NOT NULL , PRIMARY KEY (order_num) ) ENGINE=InnoDB; ####################### # Create products table ####################### CREATE TABLE products ( prod_id char(10) NOT NULL, vend_id int NOT NULL , prod_name char(255) NOT NULL , prod_price decimal(8,2) NOT NULL , prod_desc text NULL , PRIMARY KEY(prod_id) ) ENGINE=InnoDB; ###################### # Create vendors table ###################### CREATE TABLE vendors ( vend_id int NOT NULL AUTO_INCREMENT, vend_name char(50) NOT NULL , vend_address char(50) NULL , vend_city char(50) NULL , vend_state char(5) NULL , vend_zip char(10) NULL , vend_country char(50) NULL , PRIMARY KEY (vend_id) ) ENGINE=InnoDB; ########################### # Create productnotes table ########################### CREATE TABLE productnotes ( note_id int NOT NULL AUTO_INCREMENT, prod_id char(10) NOT NULL, note_date datetime NOT NULL, note_text text NULL , PRIMARY KEY(note_id), FULLTEXT(note_text) ) ENGINE=MyISAM; ##################### # Define foreign keys ##################### ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_orders FOREIGN KEY (order_num) REFERENCES orders (order_num); ALTER TABLE orderitems ADD CONSTRAINT fk_orderitems_products FOREIGN KEY (prod_id) REFERENCES products (prod_id); ALTER TABLE orders ADD CONSTRAINT fk_orders_customers FOREIGN KEY (cust_id) REFERENCES customers (cust_id); ALTER TABLE products ADD CONSTRAINT fk_products_vendors FOREIGN KEY (vend_id) REFERENCES vendors (vend_id);
######################################## # MySQL Crash Course MYSQL必知必會數據語句 # http://www.forta.com/books/0672327120/ # 提供者博客園:後青春期的Keats 複製請註明出處 ######################################## ########################## # Populate customers table ########################## INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(10001, 'Coyote Inc.', '200 Maple Lane', 'Detroit', 'MI', '44444', 'USA', 'Y Lee', 'ylee@coyote.com'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact) VALUES(10002, 'Mouse House', '333 Fromage Lane', 'Columbus', 'OH', '43333', 'USA', 'Jerry Mouse'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(10003, 'Wascals', '1 Sunny Place', 'Muncie', 'IN', '42222', 'USA', 'Jim Jones', 'rabbit@wascally.com'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact, cust_email) VALUES(10004, 'Yosemite Place', '829 Riverside Drive', 'Phoenix', 'AZ', '88888', 'USA', 'Y Sam', 'sam@yosemite.com'); INSERT INTO customers(cust_id, cust_name, cust_address, cust_city, cust_state, cust_zip, cust_country, cust_contact) VALUES(10005, 'E Fudd', '4545 53rd Street', 'Chicago', 'IL', '54545', 'USA', 'E Fudd'); ######################## # Populate vendors table ######################## INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1001,'Anvils R Us','123 Main Street','Southfield','MI','48075', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1002,'LT Supplies','500 Park Street','Anytown','OH','44333', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1003,'ACME','555 High Street','Los Angeles','CA','90046', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1004,'Furball Inc.','1000 5th Avenue','New York','NY','11111', 'USA'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1005,'Jet Set','42 Galaxy Road','London', NULL,'N16 6PS', 'England'); INSERT INTO vendors(vend_id, vend_name, vend_address, vend_city, vend_state, vend_zip, vend_country) VALUES(1006,'Jouets Et Ours','1 Rue Amusement','Paris', NULL,'45678', 'France'); ######################### # Populate products table ######################### INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('ANV01', 1001, '.5 ton anvil', 5.99, '.5 ton anvil, black, complete with handy hook'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('ANV02', 1001, '1 ton anvil', 9.99, '1 ton anvil, black, complete with handy hook and carrying case'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('ANV03', 1001, '2 ton anvil', 14.99, '2 ton anvil, black, complete with handy hook and carrying case'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('OL1', 1002, 'Oil can', 8.99, 'Oil can, red'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('FU1', 1002, 'Fuses', 3.42, '1 dozen, extra long'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('SLING', 1003, 'Sling', 4.49, 'Sling, one size fits all'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('TNT1', 1003, 'TNT (1 stick)', 2.50, 'TNT, red, single stick'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('TNT2', 1003, 'TNT (5 sticks)', 10, 'TNT, red, pack of 10 sticks'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('FB', 1003, 'Bird seed', 10, 'Large bag (suitable for road runners)'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('FC', 1003, 'Carrots', 2.50, 'Carrots (rabbit hunting season only)'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('SAFE', 1003, 'Safe', 50, 'Safe with combination lock'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('DTNTR', 1003, 'Detonator', 13, 'Detonator (plunger powered), fuses not included'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('JP1000', 1005, 'JetPack 1000', 35, 'JetPack 1000, intended for single use'); INSERT INTO products(prod_id, vend_id, prod_name, prod_price, prod_desc) VALUES('JP2000', 1005, 'JetPack 2000', 55, 'JetPack 2000, multi-use'); ####################### # Populate orders table ####################### INSERT INTO orders(order_num, order_date, cust_id) VALUES(20005, '2005-09-01', 10001); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20006, '2005-09-12', 10003); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20007, '2005-09-30', 10004); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20008, '2005-10-03', 10005); INSERT INTO orders(order_num, order_date, cust_id) VALUES(20009, '2005-10-08', 10001); ########################### # Populate orderitems table ########################### INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 1, 'ANV01', 10, 5.99); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 2, 'ANV02', 3, 9.99); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 3, 'TNT2', 5, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20005, 4, 'FB', 1, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20006, 1, 'JP2000', 1, 55); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20007, 1, 'TNT2', 100, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20008, 1, 'FC', 50, 2.50); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 1, 'FB', 1, 10); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 2, 'OL1', 1, 8.99); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 3, 'SLING', 1, 4.49); INSERT INTO orderitems(order_num, order_item, prod_id, quantity, item_price) VALUES(20009, 4, 'ANV03', 1, 14.99); ############################# # Populate productnotes table ############################# INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(101, 'TNT2', '2005-08-17', 'Customer complaint: Sticks not individually wrapped, too easy to mistakenly detonate all at once. Recommend individual wrapping.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(102, 'OL1', '2005-08-18', 'Can shipped full, refills not available. Need to order new can if refill needed.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(103, 'SAFE', '2005-08-18', 'Safe is combination locked, combination not provided with safe. This is rarely a problem as safes are typically blown up or dropped by customers.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(104, 'FC', '2005-08-19', 'Quantity varies, sold by the sack load. All guaranteed to be bright and orange, and suitable for use as rabbit bait.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(105, 'TNT2', '2005-08-20', 'Included fuses are short and have been known to detonate too quickly for some customers. Longer fuses are available (item FU1) and should be recommended.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(106, 'TNT2', '2005-08-22', 'Matches not included, recommend purchase of matches or detonator (item DTNTR).' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(107, 'SAFE', '2005-08-23', 'Please note that no returns will be accepted if safe opened using explosives.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(108, 'ANV01', '2005-08-25', 'Multiple customer returns, anvils failing to drop fast enough or falling backwards on purchaser. Recommend that customer considers using heavier anvils.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(109, 'ANV03', '2005-09-01', 'Item is extremely heavy. Designed for dropping, not recommended for use with slings, ropes, pulleys, or tightropes.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(110, 'FC', '2005-09-01', 'Customer complaint: rabbit has been able to detect trap, food apparently less effective now.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(111, 'SLING', '2005-09-02', 'Shipped unassembled, requires common tools (including oversized hammer).' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(112, 'SAFE', '2005-09-02', 'Customer complaint: Circular hole in safe floor can apparently be easily cut with handsaw.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(113, 'ANV01', '2005-09-05', 'Customer complaint: Not heavy enough to generate flying stars around head of victim. If being purchased for dropping, recommend ANV02 or ANV03 instead.' ); INSERT INTO productnotes(note_id, prod_id, note_date, note_text) VALUES(114, 'SAFE', '2005-09-07', 'Call from individual trapped in safe plummeting to the ground, suggests an escape hatch be added. Comment forwarded to vendor.' );