mysql sql wait 写法_有关SQL语句写法注意的那些事情(原创整理)
前段時候針對開發做的SQL語句寫法方面注意點的培訓,
特意總結了一下,也共享一下。
書寫SQL需要注意的若干問題(MySQL版)
一、基本問題
1,在系統中運行的SQL查詢,先考慮一下能不能在Slave上檢索,目前各個項目中Master上的不可避免的查詢量是其他所有的Slave總和還多。
但也不是一味的都是在Slave上查詢。
系統上出過一次查詢數據的情況:在一個前后順序執行的邏輯代碼中,先更新Master的數據,再在Slave上查更新后的數據,這樣的操作很多時候因服務器和網絡環境而出現查詢結果不一致的情況。這樣的就不能在Slave上查詢了。
2,盡量不要輸出沒有用的列,也不要輸出已經明確的列,增加了無用的數據傳輸量也是影響性能的。
3,盡量在每個查詢中返回自己需要的那些行,無關的不要返回。對簡單查詢是這樣,對復雜的包含很多子查詢中的每個子查詢更是這樣,盡量讓每個子查詢的結果集保留到最小再進行關聯,避免出現先關聯后再取Distinct這樣的操作。
4,盡量不要在程序里面有Select *這樣的寫法,以后表字段的順序變動都可能造成程序的問題。
5,對多表之間的連接必須用索引來作為連接列,否則這樣的查詢就是一個全表掃描,兩邊的關聯字段一定要類型一致,避免強制轉換。
mysql> explain select count(*) From JHF_ALIVE_EXECUTION E , JHF_ALIVE_CONTRACT C where C.Trade_ID=E.Trade_ID ;
+----+-------------+-------+------+-------------------+-------------------+---------+--------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+-------------------+-------------------+---------+--------------------+------+-------------+
| 1 | SIMPLE | E | ALL | NULL | NULL | NULL | NULL | 866 | |
| 1 | SIMPLE | C | ref | ALIVE_CONTRACT_02 | ALIVE_CONTRACT_02 | 42 | CFDMAIN.E.TRADE_ID | 1 | Using index |
+----+-------------+-------+------+-------------------+-------------------+---------+--------------------+------+-------------+
2 rows in set (0.00 sec)
6,不要在Where字句中對列使用函數,那樣會導致索引失效,
mysql> show index from JHF_ALIVE_CONTRACT ;
+--------------------+------------+-------------------+--------------+-------------+-----------+-------------+-+------------
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | | Index_type
+--------------------+------------+-------------------+--------------+-------------+-----------+-------------+-+------------
| JHF_ALIVE_CONTRACT | 0 | PRIMARY | 1 | CONTRACT_ID | A | 157 | | BTREE
| JHF_ALIVE_CONTRACT | 1 | ALIVE_CONTRACT_01 | 1 | ORDER_ID | A | 157 | | BTREE
| JHF_ALIVE_CONTRACT | 1 | ALIVE_CONTRACT_02 | 1 | TRADE_ID | A | 157 | | BTREE
| JHF_ALIVE_CONTRACT | 1 | ALIVE_CONTRACT_03 | 1 | CUSTOMER_ID | A | 19 | | BTREE
+--------------------+------------+-------------------+--------------+-------------+-----------+-------------+-+------------
4 rows in set (0.00 sec)
mysql>
mysql> explain select * From JHF_ALIVE_CONTRACT where Order_ID='20090930CONT00002005' ;
+----+-------------+--------------------+------+-------------------+-------------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+------+-------------------+-------------------+---------+-------+------+-------------+
| 1 | SIMPLE | JHF_ALIVE_CONTRACT | ref | ALIVE_CONTRACT_01 | ALIVE_CONTRACT_01 | 82 | const | 1 | Using where |
+----+-------------+--------------------+------+-------------------+-------------------+---------+-------+------+-------------+
1 row in set (0.00 sec)
主鍵檢索,最快的那種了。
mysql> explain select * From JHF_ALIVE_CONTRACT where substr(Order_ID,1,17) ='20090930ORD000115' ;
+----+-------------+--------------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | JHF_ALIVE_CONTRACT | ALL | NULL | NULL | NULL | NULL | 94 | Using where |
+----+-------------+--------------------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
什么索引都沒用上,全表掃描。
mysql> explain select * From JHF_ALIVE_CONTRACT where Order_ID like '20090930ORD000115%' ;
+----+-------------+--------------------+-------+-------------------+-------------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------------------+-------+-------------------+-------------------+---------+------+------+-------------+
| 1 | SIMPLE | JHF_ALIVE_CONTRACT | range | ALIVE_CONTRACT_01 | ALIVE_CONTRACT_01 | 82 | NULL | 6 | Using where |
+----+-------------+--------------------+-------+-------------------+-------------------+---------+------+------+-------------+
1 row in set (0.00 sec)
like 也能發揮索引的效果。
7,使用like語句時,對 “C%”是能利用索引的,但對 “%C”是無效的。而且在前面這個固定字符串越多時效率越好,也就盡量多匹配。
見上例。
8,Not in是個危險的用法,在程序中慎用,必要時可以用left outer
join來改寫。
9,少用點or,它很可能會使一個查詢索引失效,必要時可以用union all或者union來替代。
10,注意一下 Union all與union的區別。前者是兩個結果集的不會經過任何處理進行相加,而后者是要經過合并以后的內容。
對兩個毫不相關的集合合并時,盡量用UNION ALL,避免不必要的排序浪費系統資源。
11,在大表上不做Group by操作,如果需要的話,可以用大表的總結表。
對一些避免不了的實時檢索,可以考慮用索引覆蓋的方式來對所用到的字段全部建立索引的方式來加快查詢速度。
12,對Group by ,distinct出來的結果已經是有序的了,不需要再排序,盡量使用已經排好序的數據,免得再排序浪費資源,如果要排序,不要在Order by里面的使用表達式。
13,在java中盡量使用prepareStatement來替代Statement,一個SQL提交給MYSQL后經歷詞義檢查、語義檢查、對象檢查、獲取存取路徑、形成最終執行計劃、生成執行代碼,但是如果是兩個一樣的SQL(一模一樣,多個空格都不行)這個過程就全部省了,使用綁定變量(有的地方可能稱主機變量,就是用?來替代值,然后再設置這個值)能達到一模一樣的效果,DBMS在算存取路徑的時候會估算一個值來替代,這樣能達到一個很好的效果。(如果不注意這一點,那么你的系統離崩潰就不遠了,這點對程序員特別重要!!)但是也不是所有的情況都是這樣,對一個SQL“長時間固定不變的環境中”,那么每次執行都是相同的SQL,這時靜態變量和綁定變量方式唯一的差別是獲取存取路徑方式的不同,綁定方式是估算,而寫成變量的方式是精確的路徑。實際中到底使用哪種?1)一般都按照綁定變量來寫。2)如果在設計的時候就能明確該句在使用執行的環境,再換成靜態方式。
其實 都用綁定變量這種方式來寫,沒有什么壞處!
14,不要輕易利用MySQL的自動類型轉換,看起來挺好使,但用起來危害非常大,因為它很可能會讓看起來好端端的索引失效。
15,在數據庫上經常在允許為NULL的字段上建立了索引,注意想查詢此字段上的is null或者is not null可能會使索引失效。
16,避免出現 跨庫操作這樣的SQL語句,例如:
Use MAIN ;
Insert into
JHF_ORDER select * From HISTORY.JHF_ORDER where id=’33’ ;
這樣的SQL在Master上能正常運行的,但是因為Slave的結構各種各樣,對不存在HISTORY庫的SLAVE,這個SQL就會導致同步中斷,而一般需要人工干預才能繼續同步。
17,現有的數據庫結構中各個Slave所忽略的表是不一樣的,對類似這樣的SQL:
Insert into TA select * From TB where
Code=’ABC’,在Master上執行沒問題,但如果某個Slave忽略了TB表的同步,那么在這個Slave上的TA表的數據將也不會正常,在程序中避免出現一個Insert/Update/Delete中關聯多個表的情況,很容易因為Slave同步部分表的原因而導致數據不一致。
18,對一個大的結果結進行排序是個非常費系統資源的操作。但也不能因為這點而不排序。對一個未使用任何排序操作的結果集的默認順序是按照主鍵的順序進行默認排序的,沒有主鍵或者自增長主鍵的是按照記錄的插入先后順序進行輸出,某些時候是滿足需求的,但是這樣的排序是不可靠的,在數據庫進行過數據重整和索引重建或者后插入的數據的主鍵值不是按照一個固定的順序來的時候,就很可能打亂原始的順序而出現不用時間的不用的檢索結果。
19,關于批處理的SQL,編寫時要考慮SQL更新的速率和數據量的大小。 這主要是考慮到我們現在所使用的M/S同步機制。更新速度過快可能使數據庫壓力增大,并且出現數據庫同步延遲。更新太慢沒有效率。總之,一定要通過測試綜合進行考慮,找到平衡點以達到最好的效果。
20,不要在正式系統里面運行沒有試過的SQL語句,即使是Select語句。
A)、不恰當關聯,造成笛卡兒結果集非常龐大,讓系統忙死在寫入臨時文件的操作中,這個會發生在兩個大表間關聯的時候,關聯的條件是多對多的關系,造成結果集非常龐大,一時半會都執行不完,這時不要慌,關閉終端是解決不了問題的,進入MySQL或者在客戶端終端,按照以下命令:
show processlist ;--à找到State處于Copy to tmp ..這樣的SQL對應的Id號
kill XXXX ;
才算真正控制了這個SQL的執行。
B)、要清楚“的確”存在能把數據庫整死的純查詢SQL,看起來不起眼,但威力很大,有些是因為MySQL本身的BUG,例如:
我遇到的兩個:
SELECT COUNT(*) FROM (
SELECT Customer_ID FROM JHF_DEPOSIT
UNION ALL
SELECT Customer_ID
FROM JHF_WITHDRAWAL ORDER BY CustomerID
) A ;
(在MySQL 5.0.33中)
因為在子查詢中Order by了一個不存在的字段,不是報語句的錯誤,而是直接將MySQL數據庫重啟了。
select A.CC,A.bid,A.ask,A.rateTime,
(select ratetime From wxlTemp B where B.CC=A.CC and B.bid <> A.bid and B.ask <> A.bid and B.ratetime > A.ratetime Order by ratetime limit 1) as LastTime
From wxlTemp A
where A.RateTime
Order by A.CC,A.ratetime
這個SQL也會導致MySQL數據庫重啟。
二、有關分頁相關的:
1.分頁查詢時,通常一頁記錄為幾十條,每次只需要查詢當頁的記錄。當有復雜的查詢sql時,我們要將sql分解,提煉出必要的影響結果集的sql,用于分頁查詢,這個sql只包含一部分主要的表;在分頁查詢執行后,再查詢這一頁記錄對應的其它表的記錄。因為記錄數只有一頁了,那么其它表的查詢的性能將會很好,這部分是需要在java程序中處理的。2.如果僅僅統計表記錄數量,那么就不要使用order by。
3.對于分頁查詢,通常需要顯示符合條件的總記錄數、頁碼、當頁條數。這樣就需要執行兩次數據庫查詢,一次是計算總記錄數,一次是檢索當頁全部記錄。對于復雜sql,建議將這兩次查詢使用的sql分開。這么做的原因是,比如在FX項目中,分頁方法一般都是將sql直接進行解析,根據from來拆分成統計記錄數和返回結果集的sql。對于返回當頁記錄的sql來說,一些where條件和表關聯是必要的,因為可能其中一些只是為了在select中包含部分表的字段;但是對于統計記錄數的sql來說,只需要那些影響結果記錄數的必要條件和關聯的表即可。比如:select * from tableA inner join tableB on(tableA.c1=tableB.c1)
left outer join tableC on (tableC.c2=tableA.c2)
tableA和tableB的記錄是一對一的關系通用分頁方法會將統計記錄數的sql分解為類似下面這樣:select count(*) from tableA inner join tableB on(tableA.c1=tableB.c1)
left outer join tableC on (tableC.c2=tableA.c2)但是tableB是不需要關聯的,因為不影響記錄數。那么我們單獨寫一個統計記錄數的sql:select count(*) from tableA inner join tableB on(tableA.c1=tableB.c1)
二、如何避免出現鎖沖突及死鎖
1,對一個象Fx這樣的分布系統,同時操作注文約定邏輯幾個表這樣的模塊有很多,一定要在一個事務中確保所有的模塊對操作相同的幾個表的順序都一致,避免多個進程間對表產生死鎖。
2,對由不同的模塊更新相同的一批記錄也可能存在記錄間出現死鎖的情況,所以對事務操作比較密集的地方,盡量對操作的記錄進行按照一個統一的順序進行,比如升序或者降序。
3,對更新比較頻繁的表一定要使用INNODB的表而不要使用MyISAM,因為MyISAM的每一次更新都將是鎖住整個的表,而大大降低了更新的并發性能。
4,在現有的系統中,我們使用的事務隔離級別是:READ_COMMITED,在一個事務中它會對更新的記錄進行加鎖,這里的“更新的記錄”比較微妙,它鎖定的范圍是和更新的語句的where條件密切相關,想要達到行鎖的效果,Update語句的條件一定要加上索引,最好是主鍵或者唯一鍵,
因為這樣的鎖會很本分,確定的記錄比較明確。
5,要盡量保證事務不要過大,小事務發生鎖沖突的幾率較小。
三、如何優化
對每個SQL語句在執行之前,做一下EXPLAIN檢查,查看是否都使用了索引,是否使用了有效的索引,看是否掃描了很多行數據。
http://dev.mysql.com/doc/refman/5.1/zh/optimization.html#explain
對索引的創建也要把握精而不濫的原則,對特殊的表,可以考慮只在Slave上建立。
1,索引的建立對提高檢索能力很有用,但是數據庫維護它很費資源。
2,索引只使用開頭的部分。
key (a,b) .... where b=5
will not use index.
3,建立一個對檢索有用的索引,
index on gender is not a
good idea,例如在性別上建索引不是很有用。
4,對唯一建的索引,加上UNIQUE。
5,避免出現無用的索引。(從來沒被調用)
6,索引的順序很重要。
7,不要在同列(s)上建立兩個索引。
8,充分用別的組合索引的前面部分,是個相當好的主意。
9,可以只對一個字段的前幾個字段建立索引。
10,短一些的索引比較好,整數最好。(Short keys are better, Integer best)
11,有規律的值 比
沒有規律的隨機的數要好。
– access locality is much
better
– auto_increment better than
uuid()
12,記得經常 優化表,這樣能壓縮和排序索引項。
OPTIMIZE TABLE compact and
sort indexes
13,分析表,能更新表的統計信息,這樣對檢索很有好處。
ANALYZE TABLE - update
statistics
14.利用索引并不一定能提高性能,如果返回結果集數量很大,甚至接近全表記錄數時,那么全表掃描的效率更高。通過索引再定位到物理記錄,這個過程會比較耗費時間。
附錄:
MySQL中通過show status對得到的值進行計算得到后的值,大家可以參考。
1,連接失敗的監控.
■監視點:連接失敗的百分比。
■公式: Aborted_connects*100 / Connections
■正常范圍:小于10%.
■含義:應用程序連接服務器失敗的比例,一般原因有:未授權訪問數據庫/密碼錯誤/連接超時
等.
2,最大情況下的連接使用百分比.
■監視點:最大情況下的連接使用百分比。
■公式: Max_used_connections /
max_connections
■正常范圍:小于75%.
■含義:從開機到現在的最大連接情況,表示的是這段時間的峰值,對繁忙的系統這個很有參考意義.
3,MyISAM索引緩存命中率
■監視點: key_buffer_size的設置是否適當。
■公式: 1-(Key_reads / Key_read_requests)
■正常范圍: 95%以上.
■含義:增大key_buffer_size并且監控緩存利用率。當命中率到達了一個可接收的水平,保存key_buffer_size值到MySQL配置文件中。
需要MySQL運行一個合理時間后,查看命中率才有意義。
4,InnoDB緩存命中率
■監視點: innodb_buffer_pool_size的設置是否適當。
■公式: 100* (1 - (Innodb_buffer_pool_reads /
Innodb_buffer_pool_read_requests))
■正常范圍: 95%以上.
■含義:數據和索引在緩存中讀取的比率。從內存讀取要比磁盤讀取塊很多,因此要盡量保持物理I/O最少。
當使用InnoDB大多數的訪問應該在內存中,因此這個值要很高。
5,InnoDB緩存寫入等待率
■監視點: innodb_buffer_pool_size的設置是否適當。
■公式: 100* (Innodb_buffer_pool_wait_free /
Innodb_buffer_pool_write_requests)
■正常范圍: 1%以下.
■含義:為了最佳性能,InnoDB不應等待頁寫入到InnoDB緩沖池中。
6,InnoDB回滾日志寫入的等待比率
■監視點: innodb_log_buffer_size的設置是否適當。
■公式: 100* (Innodb_log_waits /
Innodb_log_writes)
■正常范圍: 1%以下.
■含義:為了最佳性能,InnoDB不應等待SQL操作寫入到日志。
7,線程緩存大小設定值是否合適.
■監視點: thread_cache_size的設置是否適當。
■公式: (1-Threads_created/Connections ) *100%
■正常范圍: 95%以上.
■含義:每個MySQL連接都運行在它特有的線程中。線程建立比較耗時,因此每個連接關閉的時候不是殺死線程。
服務起能保存線程在線程緩存中稍后為新的連接使用,線程緩存命中率。如果這個值太小那么就要考慮增加線程緩存的大小。
8,表打開操作是否頻繁..
■監視點: table_cache的設置是否適當。
■公式: Opened_tables的值,服務器運行一段時間后的值,要是一直在增長,那么就是有問題.
■正常范圍: 0 .
■含義: MySQL每次訪問表就把它放在表緩存中。如何系統訪問很多表那么在緩存中會更快一些。
Opened_tables就是沒有通過表緩存中打開表的數量,如果這個數值高或者增長的很快那么就需要增加table_cache的值。
9,查詢緩存碎片情況.
■監視點:查詢緩存中各個使用塊的情況,如果單個塊中有空閑的,那么此項監控就高.
■公式: 100 * Qcache_free_blocks /
Qcache_total_blocks
■正常范圍:低于70% .
■含義:如果你有很多小的查詢結果,這個值可能會很高,請考慮下面的選項:1、減少query_cache_min_res_unit值
2、執行FLUSH QUERY CACHE對查詢緩存進行碎片整理。
10,查詢修剪(從緩存中刪除,因為內存不夠)與插入查詢緩存的比率。
■監視點:從查詢緩存中刪除的總體量和插入的的比例.
■公式: Qcache_lowmem_prunes / Qcache_inserts
■正常范圍:
■含義:放入緩存的數量
與 被迫從緩存中擠出去的數量的比值.
被擠的情況有某個查詢結果集太久沒有復用,來了新的結果集,緩存中沒有空了.
也可能是,緩存的結果集涉及到的表更新比較頻繁,在下次利用的時候,
發現已經是臟的數據了,于是就擠出來,在重新裝載.
這個值能反映出
查詢緩存是不是一個穩定的查詢緩存,有沒有必要使用查詢緩存.
11,查詢緩存命中率(從緩存中刪除,因為內存不夠)與插入查詢緩存的比率。
■監視點:一個查詢的結果能被復用的比例.
■公式: Qcache_hits / (Qcache_inserts +
Qcache_hits)
■正常范圍:
■含義:查詢緩存應該為此一個高的命中率。高命中率表示其他的連接可以使用查詢緩存中結果。
低命中率說明沒有足夠的內存分配給它,或者查詢沒有在服務器上再三的執行。
12,
sort_buffer_size的大小是否合適.
■監視點:排序算法已經執行的合并的數量。如果這個變量值較大,應考慮增加sort_buffer_size系統變量的值。
■公式: Sort_merge_passes
■正常范圍:
■含義:
13,
read_rnd_buffer_size的大小是否合適.
■監視點:暫時無
■公式:
■正常范圍:
■含義:當排序后按排序后的順序讀取行時,則通過該緩沖區讀取行,避免搜索硬盤。
將該變量設置為較大的值可以大大改進ORDER BY的性能。但是,這是為每個客戶端分配的緩沖區,
因此你不應將全局變量設置為較大的值。相反,只為需要運行大查詢的客戶端更改會話變量。
14, read_rnd_buffer_size的大小是否合適.
■監視點:表鎖的次數.
■公式:Table_locks_waited / (Table_locks_waited + Table_locks_immediate)
■正常范圍:10%以內
■含義:對MyISAM表,所表是發生在讀和寫他們兩兩之間的,是并發性很低的,所以如果這個值高的話,
需要拷考慮進行表類型的更改.
15, Percentage of full table scans .
■監視點:全表掃描的比率.
■公式:(Handler_read_rnd_next + Handler_read_rnd) / (Handler_read_rnd_next +
Handler_read_rnd + Handler_read_first + Handler_read_next + Handler_read_key +
Handler_read_prev)
■正常范圍:20%以內
■含義:要盡力保持很小的值。設法隔離沒使用索引的查詢。使用慢查詢日志記錄哪些運行時間較長的查詢。
16, Select_full_join .
■監視點:沒有使用索引的聯接的數量.
■公式:Select_full_join
■正常范圍:20%以內
■含義:沒有使用索引的聯接的數量。如果該值不為0,你應仔細檢查表的索引。。
17, binlog_cache_size的大小是否合適.
■監視點:表鎖的次數.
■公式:Binlog_cache_disk_use / Binlog_cache_use
■正常范圍:10%以內
■含義:增加這個值并且監控這個值。當命中率達到可以接受的水平將binlog_cache_size參數添加到MySQL配置文件中。
18, tmp_table_size,max_heap_table_size的大小是否合適.
■監視點:使用臨時表的次數.
■公式:Created_tmp_disk_tables / Created_tmp_tables
■正常范圍:50%以內
■含義:如果這個值太高了那么就要考慮增加tmp_table_size和max_heap_table_size大小。
臨時表的TEXT or BLOBS字段要保存在磁盤上,因此設法改變TEXT或者BLOBS字段類型。
(完)
總結
以上是生活随笔為你收集整理的mysql sql wait 写法_有关SQL语句写法注意的那些事情(原创整理)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win7电脑内外网切换(一台电脑切换内外
- 下一篇: mysql explain output