close

MySQL查詢進行優化
資料庫管理員工作中常會遇到讓單獨的查詢執行的速度變快。MySQL還允許你改變語句調度的優先順序,它可以使來自多個用戶端的查詢更好地協作,這樣單個用戶端就不會由於鎖定而等待很長時間。改變優先順序還可以確保特定類型的查詢被處理得更快。下麵我們來講解MySQL的預設的調度策略和可以用來影響這些策略的選項。還有併發性插入操作的使用和存儲引擎鎖定層次對用戶端的併發性的影響。為了討論的方便,我們把執行檢索(SELECT)的用戶端稱為"讀取者",把執行修改操作(DELETE、INSERT、REPLACE或UPDATE)的用戶端稱為"寫入者"。

 

  MySQL的預設的調度策略可用總結如下:

  寫入操作優先于讀取操作。

  對某張資料表的寫入操作某一時刻只能發生一次,寫入請求按照它們到達的次序來處理。

  對某張資料表的多個讀取操作可以同時地進行。

  MyISAM和MEMORY存儲引擎借助于資料表鎖來實現這樣的調度策略。當用戶端訪問某張表的時候,首先必須獲取它的鎖。當用戶端完成對表的操作的時候,鎖就會被解除。通過LOCK TABLES和UNLOCK TABLES語句來顯式地獲取或釋放鎖是可行的,但是在通常情況下,伺服器的鎖管理器會自動地在需要的時候獲取鎖,在不再需要的時候釋放鎖。獲取的鎖的類型依賴于用戶端是寫入還是讀取操作。

  對某張表進行寫入操作的用戶端必須擁有獨佔的(排他的)訪問權的鎖。操作在進行的過程中,該資料表處於不一致的(inconsistent)狀態,因為資料記錄在刪除、添加或修改的時候,資料表上的索引也可能需要更新以相互匹配。這個資料表在變化的過程中,如果允許其它的用戶端訪問,會出現問題。非常明顯,允許兩個用戶端同時寫入一張資料表是不利的,因為這樣的操作會很快使資料表中的資訊成為一堆無用的垃圾。但是允許用戶端讀取變化之中的資料表也不好,因為正在讀取的位置中的資料可能正在變化(修改),讀取的結果可能不是真實的。

  對某張表執行讀取操作的用戶端必須獲取一個鎖,防止在讀取的過程中,其它的用戶端寫入或改變表。但是這個鎖不需要獨佔的訪問權。讀取操作不會改變數據,因此沒有理由讓某個讀取者阻止其它的讀取者訪問這張表。因此讀取鎖允許其它的用戶端在同一時刻讀取這張表。

  MySQL提供了幾個語句調節符,允許你修改它的調度策略:

  LOW_PRIORITY關鍵字應用於DELETE、INSERT、LOAD DATA、REPLACE和UPDATE。

  HIGH_PRIORITY關鍵字應用於SELECT和INSERT語句。

  DELAYED關鍵字廣告應用於INSERT和REPLACE語句。

  LOW_PRIORITY和HIGH_PRIORITY調節符影響那些使用資料表鎖的存儲引擎(例如MyISAM和MEMORY)。DELAYED調節符作用於MyISAM和MEMORY資料表。

 改變語句調度的優先順序

  LOW_PRIORITY關鍵字影響DELETE、INSERT、LOAD DATA、REPLACE和UPDATE語句的執行調度。通常情況下,某張資料表正在被讀取的時候,如果有寫入操作到達,那麼寫入者一直等待讀取者完成操作(查詢開始之後就不能中斷,因此允許讀取者完成操作)。如果寫入者正在等待的時候,另一個讀取操作到達了,該讀取操作也會被阻塞(block),因為預設的調度策略是寫入者優先于讀取者。當第一個讀取者完成操作的時候,寫入者開始操作,並且直到該寫入者完成操作,第二個讀取者才開始操作。

  如果寫入操作是一個LOW_PRIORITY(低優先順序)請求,那麼系統就不會認為它的優先順序高於讀取操作。在這種情況下,如果寫入者在等待的時候,第二個讀取者到達了,那麼就允許第二個讀取者插到寫入者之前。只有在沒有其它的讀取者的時候,才允許寫入者開始操作。理論上,這種調度修改暗示著,可能存在LOW_PRIORITY寫入操作永遠被阻塞的情況。如果前面的讀取操作在進行的過程中一直有其它的讀取操作到達,那麼新的請求都會插入到LOW_PRIORITY寫入操作之前。

  SELECT查詢的HIGH_PRIORITY(高優先順序)關鍵字廣告也類似。它允許SELECT插入正在等待的寫入操作之前,即使在正常情況下寫入操作的優先順序更高。另外一種影響是,高優先順序的SELECT在正常的SELECT語句之前執行,因為這些語句會被寫入操作阻塞。

  如果你希望所有支援LOW_PRIORITY選項的語句都預設地按照低優先順序來處理,那麼請使用--low-priority-updates選項來啟動伺服器。通過使用INSERT HIGH_PRIORITY來把INSERT語句提高到正常的寫入優先順序,可以消除該選項對單個INSERT語句的影響。

 

使用延遲插入操作

  DELAYED調節符應用於INSERT和REPLACE語句。當DELAYED插入操作到達的時候,伺服器把資料行放入一個佇列中,並立即給用戶端返回一個狀態資訊,這樣用戶端就可以在資料表被真正地插入記錄之前繼續進行操作了。如果讀取者從該資料表中讀取資料,佇列中的資料就會被保持著,直到沒有讀取者為止。接著伺服器開始插入延遲資料行(delayed-row)佇列中的資料行。在插入操作的同時,伺服器還要檢查是否有新的讀取請求到達和等待。如果有,延遲資料行佇列就被掛起,允許讀取者繼續操作。當沒有讀取者的時候,伺服器再次開始插入延遲的資料行。這個過程一直進行,直到佇列空了為止。

  感覺上LOW_PRIORITY和DELAYED是相似的,兩者都允許資料行插入操作被延遲,但是它們對用戶端操作的影響卻有很大的差異。LOW_ PRIORITY強迫用戶端等待,直到那些資料行可以被插入資料表。DELAYED允許用戶端繼續操作,伺服器在記憶體中緩衝那些資料行,直到自己有時間處理它們。

  如果其它的用戶端可能運行很長的SELECT語句並且你不希望阻塞,等待插入操作完成的時候,INSERT DELAYED就非常有用處了。用戶端提交INSERT DELAYED的時候可能處理得很快,因為伺服器只是簡單地把要插入的資料行排隊。

  但是,你也必須知道正常的INSERT與INSERT DELAYED行為之間的一些其它的差異。如果INSERT DELAYED語句包含語法錯誤,用戶端會得到一個錯誤,關鍵字廣告但是卻無法得到其它一些在正常情況下可以使用的資訊。例如,當語句返回的時候,你無法依賴(得到)AUTO_INCREMENT(自動增長)值。同樣,你無法得到唯一索引的副本數量。發生這種情況的原因在於插入操作在真正地被執行之前已經返回了狀態資訊。另一種可能出現的情況是,由於INSERT DELAYED語句的資料行都在記憶體中排隊,當伺服器崩潰或者使用kill -9退出的時候,資料行可能丟失(正常情況下,kill -TERM終止命令不會導致這種情況,因為伺服器在退出之前會把資料行插入表中)。

arrow
arrow
    全站熱搜

    tupian11 發表在 痞客邦 留言(0) 人氣()