MYSQL資料庫------SQL優化
sql優化
- 對查詢進行優化,應儘量避免全表掃描,首先應考慮在where及order by,GROUP BY涉及的列上建立索引。
- 對查詢進行優化,應儘量避免全表掃描,首先應考慮在where及order by涉及的列上建立索引。
- 應儘量避免在where子句中使用!=或<>操作符,MySQL只有對以下操作符才使用索引:<,<=,=,>,>=,BETWEEN,IN,以及某些時候的LIKE。
- 應儘量避免在where子句中使用or來連線條件,否則將導致引擎放棄使用索引而進行全表掃描,可以使用UNION合併查詢:select id from t where num=10 union all select id from t where num=20。
- in和not in也要慎用,否則會導致全表掃描,對於連續的數值,能用between就不要用in了:Select id from t where num between 1 and 3
- 下面的查詢也將導致全表掃描:select id from t where name like‘%abc%’或者select id from t where name like‘%abc’若要提高效率,可以考慮全文檢索。而select id from t where name like‘abc%’才用到索引。
- 如果在where子句中使用引數,也會導致全表掃描。
- 很多時候用exists代替in是一個好的選擇:select num from a where num in(select num from b)。用下面的語句替換:select num from a where exists(select 1 from b where num=a.num)。
- 索引固然可以提高相應的select的效率,但同時也降低了insert及update的效率,因為insert或update時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。一個表的索引數最好不要超過6個,若太多則應考慮一些不常使用到的列上建的索引是否有必要。
- 最好不要使用”“返回所有:select from t ,用具體的欄位列表代替“*”,不要返回用不到的任何欄位。
- 最好不要使用”“返回所有:select from t ,用具體的欄位列表代替“*”,不要返回用不到的任何欄位。
- 在IN後面值的列表中,將出現最頻繁的值放在最前面,出現得最少的放在最後面,減少判斷的次數。
- 儘量使用exists代替select count(1)來判斷是否存在記錄,count函式只有在統計表中所有行數時使用,而且count(1)比count(*)更有效率。 count(*)它可能鎖住整張表
- 當有一批處理的插入或更新時,用批量插入或批量更新,絕不會一條條記錄的去更新。
- 當只要一行資料時使用LIMIT 1,這樣查詢到以後就不會繼續查詢了
- 在適當的情形下使用GROUP BY而不是DISTINCT
- 提高GROUP BY語句的效率,可以通過將不需要的記錄在GROUP BY之前過濾掉。下面兩個查詢返回相同結果,但第二個明顯就快了許多。
SELECT JOB , AVG(SAL)
FROM EMP
GROUP BY JOB
HAVING JOB =’PRESIDENT’
OR JOB =’MANAGER’
SELECT JOB , AVG(SAL)
FROM EMP
WHERE JOB =’PRESIDENT’
OR JOB =’MANAGER’
GROUP BY JOB
儘量避免使用子查詢
以下查詢返回月薪大於部門平均月薪的員工資訊
EXPLAIN ANALYZE
SELECT emp_id, emp_name
FROM employee e
WHERE salary > (
SELECT AVG(salary)
FROM employee
WHERE dept_id = e.dept_id);
- 從執行計劃可以看出,MySQL 中採用的是類似 Nested Loop Join 實現方式;子查詢迴圈了 25 次,而實際上可以通過一次掃描計算並快取每個部門的平均月薪。以下語句將該子查詢替換為等價的 JOIN 語句,實現了子查詢的展開(Subquery Unnest):
EXPLAIN ANALYZE
SELECT e.emp_id, e.emp_name
FROM employee e
JOIN (SELECT dept_id, AVG(salary) AS dept_average
FROM employee
GROUP BY dept_id) t
ON e.dept_id = t.dept_id
WHERE e.salary > t.dept_average;
- 改寫之後的查詢利用了物化(Materialization)技術,將子查詢的結果生成一個記憶體臨時表;然後與 employee 表進行連線。通過實際執行時間可以看出這種方式更快。
們應該儘量避免使用子查詢,考慮使用 JOIN 進行重寫。
瞭解 SQL 子句的邏輯執行順序
以下是 SQL 中各個子句的語法順序,前面括號內的數字代表了它們的邏輯執行順序:
(6)SELECT [DISTINCT | ALL] col1, col2, agg_func(col3) AS alias
(1) FROM t1 JOIN t2
(2) ON (join_conditions)
(3) WHERE where_conditions
(4) GROUP BY col1, col2
(5)HAVING having_condition
(7) UNION [ALL]
...
(8) ORDER BY col1 ASC,col2 DESC
(9)OFFSET m ROWS FETCH NEXT num_rows ROWS ONLY;
- 首先,FROM 和 JOIN 是 SQL 語句執行的第一步。它們的邏輯結果是一個笛卡爾積,決定了接下來要操作的資料集。注意邏輯執行順序並不代表物理執行順序,實際上資料庫在獲取表中的資料之前會使用 ON 和 WHERE 過濾條件進行優化訪問;
- 其次,應用 ON 條件對上一步的結果進行過濾並生成新的資料集;
- 然後,執行 WHERE 子句對上一步的資料集再次進行過濾。WHERE 和 ON 大多數情況下的效果相同,但是外連線查詢有所區別,我們將會在下文給出示例;
- 接著,基於 GROUP BY 子句指定的表示式進行分組;同時,對於每個分組計算聚合函式 agg_func 的結果。經過 GROUP BY 處理之後,資料集的結構就發生了變化,只保留了分組欄位和聚合函式的結果;
- 如果存在 GROUP BY 子句,可以利用 HAVING 針對分組後的結果進一步進行過濾,通常是針對聚合函式的結果進行過濾;
- 接下來,SELECT 可以指定要返回的列;如果指定了 DISTINCT 關鍵字,需要對結果集進行去重操作。另外還會為指定了 AS 的欄位生成別名;
- 如果還有集合操作符(UNION、INTERSECT、EXCEPT)和其他的 SELECT 語句,執行該查詢並且合併兩個結果集。對於集合操作中的多個 SELECT 語句,資料庫通常可以支援併發執行;
- 然後,應用 ORDER BY 子句對結果進行排序。如果存在 GROUP BY 子句或者 DISTINCT 關鍵字,只能使用分組欄位和聚合函式進行排序;否則,可以使用 FROM 和 JOIN 表中的任何欄位排序;
- 最後,OFFSET 和 FETCH(LIMIT、TOP)限定了最終返回的行數。
優化表的資料型別,選擇合適的資料型別:
- 原則:更小通常更好,簡單就好,所有欄位都得有預設值,儘量避免null。
- 資料庫表設計時候更小的佔磁碟空間儘可能使用更小的整數型別。(mediumint就比int更合適)
- 時間欄位:datetime和timestamp,datetime佔用8個位元組,而timestamp佔用4個位元組,只用了一半,而timestamp表示的範圍是1970—2037適合做更新時間
- MySQL可以很好的支援大資料量的存取,但是一般說來,資料庫中的表越小,在它上面執行的查詢也就會越快。
因此,在建立表的時候,為了獲得更好的效能,我們可以將表中欄位的寬度設得儘可能小。
例如:在定義郵政編碼這個欄位時,如果將其設定為CHAR(255),顯然給資料庫增加了不必要的空間。甚至使用VARCHAR這種型別也是多餘的,因為CHAR(6)就可以很好的完成任務了。
如果可以的話,我們應該使用MEDIUMINT而不是BIGIN來定義整型欄位,應該儘量把欄位設定為NOT NULL,這樣在將來執行查詢的時候,資料庫不用去比較NULL值。
對於某些文字欄位,例如“省份”或者“性別”,我們可以將它們定義為ENUM型別。因為在MySQL中,ENUM型別被當作數值型資料來處理,而數值型資料被處理起來的速度要比文字型別快得多。這樣,我們又可以提高資料庫的效能。
varchar,char,text的區別
- char是定長的,也就是當你輸入的字元小於你指定的數目時,char(8),你輸入的字元小於8時,它會再後面補空值。當你輸入的字元大於指定的數時,它會擷取超出的字元。
- varchar長度為 n 個位元組的可變長度且非 Unicode 的字元資料。n 必須是一個介於 1 和 8,000 之間的數值。儲存大小為輸入資料的位元組的實際長度,而不是 n 個位元組。所輸入的資料字元長度可以為零。
- text儲存可變長度的非Unicode資料,最大長度為2^31-1(2,147,483,647)個字元。
如果能確定字元長度(比如身份證號)用char型別,反之用varchar
一定要用explain測試自己的sql
主要關注Select_type
Select_type 說明查詢中使用到的索引型別,如果沒有用有用到索引則為all
常用的型別有: ALL, index, range, ref, eq_ref, const, system, NULL(從左到右,效能從差到好)
ALL:Full Table Scan, MySQL將遍歷全表以找到匹配的行
index: Full Index Scan,index與ALL區別為index型別只遍歷索引樹(建立索引,但是如果沒有規範的使用索引,就是index型別 比如(%param%)查詢的就是index)
range:只檢索給定範圍的行,使用一個索引來選擇行
ref: 表示上述表的連線匹配條件,即哪些列或常量被用於查詢索引列上的值
eq_ref: 類似ref,區別就在使用的索引是唯一索引,對於每個索引鍵值,表中只有一條記錄匹配,簡單來說,就是多表連線中使用primary key或者 unique key作為關聯條件
const、system: 當MySQL對查詢某部分進行優化,並轉換為一個常量時,使用這些型別訪問。如將主鍵置於where列表中,MySQL就能將該查詢轉換為一個常量,system是const型別的特例,當查詢的表只有一行的情況下,使用system
NULL: MySQL在優化過程中分解語句,執行時甚至不用訪問表或索引,例如從一個索引列裡選取最小值可以通過單獨索引查詢完成。
相關文章
- MySQL 資料庫與 SQL 優化MySql資料庫優化
- 資料庫優化 - SQL優化資料庫優化SQL
- 資料庫優化SQL資料庫優化SQL
- MySQL資料庫優化MySql資料庫優化
- 【資料庫】優化SQL語言資料庫優化SQL
- 【資料庫】MySQL查詢優化資料庫MySql優化
- 資料庫效能優化-索引與sql相關優化資料庫優化索引SQL
- 基於mysql資料庫 關於sql優化的一些問題MySql資料庫優化
- MySql的資料庫優化到底優化啥了都(3)MySql資料庫優化
- MySQL優化篇(一),我可以和麵試官多聊幾句嗎?——SQL優化流程與優化資料庫物件MySql優化資料庫物件
- MySQL資料庫的索引原理、與慢SQL優化的5大原則MySql資料庫索引優化
- MySQL-SQL優化MySql優化
- MySql的資料庫優化到底優啥了都??(2)MySql資料庫優化
- MySQL資料庫基礎知識及優化MySql資料庫優化
- 提高mysql千萬級大資料SQL查詢優化30條經驗(Mysql索引優化注意)MySql大資料優化索引
- 資料庫優化資料庫優化
- 資料庫sql的優化問題的面試題資料庫SQL優化面試題
- 【資料庫學習】資料庫平臺:mysql,sql server資料庫MySqlServer
- MYSQL SQL語句優化MySql優化
- MySQL SQL優化案例(一)MySql優化
- MySQL之SQL優化技巧MySql優化
- MySQL資料庫優化分析MySql資料庫優化
- MySQL資料庫優化:縮小資料的五點建議VCMySql資料庫優化
- 百萬資料 mysql count(*)優化MySql優化
- 資料庫系列:MySQL索引優化總結(綜合版)資料庫MySql索引優化
- 1.4 資料庫和常用SQL語句(正文)——MySQL資料庫命令和SQL語句資料庫MySql
- MySQL之SQL語句優化MySql優化
- Mysql慢SQL分析及優化MySql優化
- 資料庫優化之臨時表優化資料庫優化
- 資料庫優化建議資料庫優化
- 百萬級資料庫優化資料庫優化
- 資料庫查詢優化資料庫優化
- 資料庫效能優化2資料庫優化
- 【MySQL】資料庫最佳化MySql資料庫
- mysql資料庫最佳化MySql資料庫
- MySQL資料SQL優化中,索引不被使用的典型場景總結MySql優化索引
- 資料庫SQL調優的幾種方式資料庫SQL
- SQL、Mysql、資料庫到底什麼關係MySql資料庫