少年阿賓

          那些青春的歲月

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

          #

          反射只能讀取類信息,而 ASM 除了讀還能寫。
          反射讀取類信息時需要進行類加載處理,而 ASM 則不需要將類加載到內存中。
          反射相對于 ASM 來說使用方便,想直接操縱 ASM 的話需要有 JVM 指令基礎。  
          反射是讀取持久堆上存儲的類信息。而 ASM 是直接處理 .class 字節碼的小工具(工具雖小,但是功能非常強大!) 
          posted @ 2015-04-03 18:20 abin 閱讀(1221) | 評論 (0)編輯 收藏

           If you are not sure about the string pool usage, try -XX:+PrintStringTableStatistics JVM argument. It will print you the string pool usage when your program terminates.
          posted @ 2015-03-31 18:22 abin 閱讀(337) | 評論 (0)編輯 收藏

          基本概念:
                在軟件系統中,“行為請求者”與“行為實現者”通常呈現一種“緊耦合”。但在某些場合,比如要對行為進行“記錄、撤銷/重做、事務”等處理,這種無法抵御變化的緊耦合是不合適的。在這種情況下,如何將“行為請求者”與“行為實現者”解耦?將一組行為抽象為對象實現二者之間的松耦合。這就是命令模式(Command Pattern)。

               將來自客戶端的請求傳入一個對象,從而使你可用不同的請求對客戶進行參數化。用于“行為請求者”與“行為實現者”解耦,可實現二者之間的松耦合,以便適應變化。分離變化與不變的因素。

             在面向對象的程序設計中,一個對象調用另一個對象,一般情況下的調用過程是:創建目標對象實例;設置調用參數;調用目標對象的方法。

          但在有些情況下有必要使用一個專門的類對這種調用過程加以封裝,我們把這種專門的類稱作command類。


          特點
          1)、command模式將調用操作的對象和實現該操作的對象解耦
          2)、可以將多個命令裝配成一個復合命令,復合命令是Composite模式的一個實例
          3)、增加新的command很容易,無需改變已有的類

          應用場景:

          我們來分析下命令模式的使用場景吧,一般情況下如下幾類場景中使用命令模式會達到很好的效果:

                1、當一個應用程序調用者與多個目標對象之間存在調用關系時,并且目標對象之間的操作很類似的時候。

                2、例如當一個目標對象內部的方法調用太復雜,或者內部的方法需要協作才能完成對象的某個特點操作時。

                3、有時候調用者調用目標對象后,需要回調一些方法。

               命令模式是將行為請求者和行為實現者解耦合的方式。對命令進行封裝,將命令和執行命令分隔開。請求的一方發出命令,要求執行某些操作,接受一方收到命令,執行這些操作的真正實現。請求的一方不必知道接受方的接口,以及如何被操作。 


              命令模式可以應用到很多場景,比如實現do/undo功能、實現導航功能。

          posted @ 2015-03-30 21:23 abin 閱讀(2159) | 評論 (2)編輯 收藏

          ApplicationContext 是 BeanFactory 接口的子接口,它增強了 BeanFactory 的功能,處于 context 包下。很多時候, ApplicationContext 允許以聲明式方式操作容器,無須手動創建。可利用如 ContextLoader 的支持類,在 Web 應用啟動時自動創建 ApplicationContext。當然,也可以采用編程方式創建 ApplicationContext。

          ApplicationContext包括BeanFactory的全部功能,因此建議優先使用ApplicationContext。除非對于某些內存非常關鍵的應用,才考慮使用 BeanFactory。

          spring為ApplicationContext提供的3種實現分別為:

          1、  ClassPathXmlApplicationContext:利用類路徑的XML文件來載入Bean定義的信息

          [1]  ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");

          [2]  String[] locations = {"bean1.xml", "bean2.xml", "bean3.xml"};

          ApplicationContext ctx = new ClassPathXmlApplication(locations);

          2、 FileSystemXmlApplicationContext:利用文件系統中的XMl文件來載入Bean

          定義的信息

          [1]  ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml"); //加載單個配置文件

          [2]  String[] locations = {"bean1.xml", "bean2.xml", "bean3.xml"};

           ApplicationContext ctx = new FileSystemXmlApplicationContext(locations );

          //加載多個配置文件

          [3]  ApplicationContext ctx =new FileSystemXmlApplicationContext("D:/project/bean.xml");

          //根據具體路徑加載

          3、 XmlWebApplicationContext:從Web系統中的XML文件來載入Bean定義的信息。

           ServletContext servletContext = request.getSession().getServletContext();    

           ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);

           

           

          配置WebApplicationContext的兩種方法:

          (1)        利用Listener接口來實現

          <listener>

                 <listener-class>

          org.springframework.web.context.ContextLoaderListener

          </listener-class>

          </listener>

          <context-param>

                 <param-name>contextConfigLocation</param-name>

                 <param-value>classpath:applicationContext</param-value>

          </context-param>

          (2)        利用Servlet接口來實現

          <context-param>

          <param-name>contextConfigLocation</param-name>

          <param-value>classpath:applicationContext</param-value>

          </context-param>

          <Servlet>

                 <servlet-name>context</servlet-name>

                 <servlet-class>

                     org.springframework.web.context.ContextLoaderServlet

                 </servlet-class>

          </servlet>

          posted @ 2015-03-27 14:53 abin 閱讀(407) | 評論 (0)編輯 收藏

          裝飾者模式(Decorator Pattern),是在不必改變原類文件和使用繼承的情況下,動態的擴展一個對象的功能。它是通過創建一個包裝對象,也就是裝飾來包裹真實的對象。
          使用裝飾者模式的時候需要注意一下幾點內容:
          (1)裝飾對象和真實對象有相同的接口。這樣客戶端對象就可以以和真實對象相同的方式和裝飾對象交互。
          (2)裝飾對象包含一個真實對象的引用。
          (3)裝飾對象接受所有的來自客戶端的請求,它把這些請求轉發給真實的對象。
          (4)裝飾對象可以在轉發這些請求以前或以后增加一些附加功能。這樣就確保了在運行時,不用修改給定對象的結構就可以在外部增加附加的功能。在面向對象的設計中,通常是通過繼承來實現對給定類的功能擴展。然而,裝飾者模式,不需要子類可以在應用程序運行時,動態擴展功能,更加方便、靈活。

          適用裝飾者模式場合:
          1.當我們需要為某個現有的對象,動態的增加一個新的功能或職責時,可以考慮使用裝飾模式。
          2.當某個對象的職責經常發生變化或者經常需要動態的增加職責,避免為了適應這樣的變化,而增加繼承子類擴展的方式,因為這種方式會造成子類膨脹的速度過快,難以控制。

          推薦你一本設計模式方面的優秀書籍:鄭阿奇 主編的《軟件秘笈-設計模式那點事》。里面講解很到位,實例通俗易懂,看了收獲很大!

          posted @ 2015-03-27 00:11 abin 閱讀(908) | 評論 (0)編輯 收藏

          二分查找的基本思想是將n個元素分成大致相等的兩部分,去a[n/2]與x做比較,如果x=a[n/2],則找到x,算法中止;如果x<a[n/2],則只要在數組a的左半部分繼續搜索x,如果x>a[n/2],則只要在數組a的右半部搜索x.

          時間復雜度無非就是while循環的次數!

          總共有n個元素,

          漸漸跟下去就是n,n/2,n/4,....n/2^k,其中k就是循環的次數

          由于你n/2^k取整后>=1

          即令n/2^k=1

          可得k=log2n,(是以2為底,n的對數)

          所以時間復雜度可以表示O()=O(logn)

          posted @ 2015-03-26 16:30 abin 閱讀(641) | 評論 (0)編輯 收藏

          Static 靜態:這里主要記錄的是靜態程序塊和靜態方法

          如果有些代碼必須在項目啟動的時候就執行,就需要使用靜態代碼塊,這種代碼是主動執行的;需要在項目啟動的時候就初始化但是不執行,在不創建對象的情況下,可以供其他程序調用,而在調用的時候才執行,這需要使用靜態方法,這種代碼是被動執行的. 靜態方法在類加載的時候 就已經加載 可以用類名直接調用。

          靜態代碼塊和靜態方法的區別是:

          靜態代碼塊是自動執行的;

          靜態方法是被調用的時候才執行的.

          靜態方法:如果我們在程序編寫的時候需要一個不實例化對象就可以調用的方法,我們就可以使用靜態方法,具體實現是在方法前面加上static,如下:

          public static void method(){}

          在使用靜態方法的時候需要注意一下幾個方面:

          在靜態方法里只能直接調用同類中其他的靜態成員(包括變量和方法),而不能直接訪問類中的非靜態成員。這是因為,對于非靜態的方法和變量,需要先創建類的實例對象后才可使用,而靜態方法在使用前不用創建任何對象。(備注:靜態變量是屬于整個類的變量而不是屬于某個對象的)

          靜態方法不能以任何方式引用this和super關鍵字,因為靜態方法在使用前不用創建任何實例對象,當靜態方法調用時,this所引用的對象根本沒有產生。

          靜態程序塊:當一個類需要在被載入時就執行一段程序,這樣可以使用靜態程序塊。

          public class DemoClass {

          private DemoClass(){}

          public static DemoClass _instance;

          static{

          if(null == _instance ){

          _instance = new DemoClass();

          }

          }

          public static DemoClass getInstance(){

          return _instance;

          }

          }

          這樣的程序在類被加載的時候就執行了static中的代碼。

          Ps:java中類的裝載步驟:

          在Java中,類裝載器把一個類裝入Java虛擬機中,要經過三個步驟來完成:裝載、鏈接和初始化,其中鏈接又可以分成校驗、準備和解析三步,除了解析外,其它步驟是嚴格按照順序完成的,各個步驟的主要工作如下:

          所謂裝載就是尋找一個類或是一個接口的二進制形式并用該二進制形式來構造代表這個類或是這個接口的class對象的過程。其中類或接口的名稱是給定了的。

          裝載:查找和導入類或接口的二進制數據;

          鏈接:執行下面的校驗、準備和解析步驟,其中解析步驟是可以選擇的;

          校驗:檢查導入類或接口的二進制數據的正確性;

          準備:給類的靜態變量分配并初始化存儲空間;

          解析:將符號引用轉成直接引用;

          初始化:激活類的靜態變量的初始化Java代碼和靜態Java代碼塊

          posted @ 2015-03-25 15:24 abin 閱讀(335) | 評論 (0)編輯 收藏

          replication的限制:一旦數據庫過于龐大,尤其是當寫入過于頻繁,很難由一臺主機支撐的時候,我們還是會面臨到擴展瓶頸。數據切分(sharding):通過某種特定的條件,將我們存放在同一個數據庫中的數據分散存放到多個數據庫(主機)上面,以達到分散單臺設備負載的效果。。數據的切分同時還可以提高系統的總體可用性,因為單臺設備Crash之后,只有總體數據的某部分不可用,而不是所有的數據。

          數據的切分(Sharding)模式

          一種是按照不同的表(或者Schema)來切分到不同的數據庫(主機)之上,這種切可以稱之為數據的垂直(縱向)切分;另外一種則是根據表中的數據的邏輯關系,將同一個表中的數據按照某種條件拆分到多臺數據庫(主機)上面,這種切分稱之為數據的水平(橫向)切分。

          垂直切分:

          一個架構設計較好的應用系統,其總體功能肯定是由很多個功能模塊所組成的,而每一個功能模塊所需要的數據對應到數據庫中就是一個或者多個表。而在架構設計中,各個功能模塊相互之間的交互點越統一越少,系統的耦合度就越低,系統各個模塊的維護性以及擴展性也就越好。這樣的系統,實現數據的垂直切分也就越容易。

          一般來說,如果是一個負載相對不是很大的系統,而且表關聯又非常的頻繁,那可能數據庫讓步,將幾個相關模塊合并在一起減少應用程序的工作的方案可以減少較多的工作量,這是一個可行的方案。一個垂直拆分的例子:

          1.用戶模塊表:user,user_profile,user_group,user_photo_album
          2.群組討論表:groups,group_message,group_message_content,top_message
          3.相冊相關表:photo,photo_album,photo_album_relation,photo_comment
          4.事件信息表:event


          • 群組討論模塊和用戶模塊之間主要存在通過用戶或者是群組關系來進行關聯。一般關聯的時候都會是通過用戶的id或者nick_name以及group的id來進行關聯,通過模塊之間的接口實現不會帶來太多麻煩;
          • 相冊模塊僅僅與用戶模塊存在通過用戶的關聯。這兩個模塊之間的關聯基本就有通過用戶id關聯的內容,簡單清晰,接口明確;
          • 事件模塊與各個模塊可能都有關聯,但是都只關注其各個模塊中對象的ID信息,同樣可以做到很容易分拆。

          垂直切分的優點

          • 數據庫的拆分簡單明了,拆分規則明確;
          • 應用程序模塊清晰明確,整合容易;
          • 數據維護方便易行,容易定位;

          垂直切分的缺點


          • 部分表關聯無法在數據庫級別完成,需要在程序中完成
          • 對于訪問極其頻繁且數據量超大的表仍然存在性能瓶頸,不一定能滿足要求;
          • 事務處理相對更為復雜
          • 切分達到一定程度之后,擴展性會遇到限制;
          • 過讀切分可能會帶來系統過渡復雜而難以維護。

          水平切分

          將某個訪問極其頻繁的表再按照某個字段的某種規則來分散到多個表之中,每個表中包含一部分數據。

          對于上面的例子:所有數據都是和用戶關聯的,那么我們就可以根據用戶來進行水平拆分,將不同用戶的數據切分到不同的數據庫中。

          現在互聯網非常火爆的Web2.0類型的網站,基本上大部分數據都能夠通過會員用戶信息關聯上,可能很多核心表都非常適合通過會員ID來進行數據的水平切分。而像論壇社區討論系統,就更容易切分了,非常容易按照論壇編號來進行數據的水平切分。切分之后基本上不會出現各個庫之間的交互。

          水平切分的優點


          • 表關聯基本能夠在數據庫端全部完成;
          • 不會存在某些超大型數據量和高負載的表遇到瓶頸的問題;
          • 應用程序端整體架構改動相對較少;
          • 事務處理相對簡單;
          • 只要切分規則能夠定義好,基本上較難遇到擴展性限制;

          水平切分的缺點

          • 切分規則相對更為復雜,很難抽象出一個能夠滿足整個數據庫的切分規則;
          • 后期數據的維護難度有所增加,人為手工定位數據更困難;
          • 應用系統各模塊耦合度較高,可能會對后面數據的遷移拆分造成一定的困難。

          兩種切分結合用:

          一般來說,我們數據庫中的所有表很難通過某一個(或少數幾個)字段全部關聯起來,所以很難簡單的僅僅通過數據的水平切分來解決所有問題。而垂直切分也只能解決部分問題,對于那些負載非常高的系統,即使僅僅只是單個表都無法通過單臺數據庫主機來承擔其負載。我們必須結合“垂直”和“水平”兩種切分方式同時使用

          每一個應用系統的負載都是一步一步增長上來的,在開始遇到性能瓶頸的時候,大多數架構師和DBA都會選擇先進行數據的垂直拆分,因為這樣的成本最先,最符合這個時期所追求的最大投入產出比。然而,隨著業務的不斷擴張,系統負載的持續增長,在系統穩定一段時期之后,經過了垂直拆分之后的數據庫集群可能又再一次不堪重負,遇到了性能瓶頸。

          如果我們再一次像最開始那樣繼續細分模塊,進行數據的垂直切分,那我們可能在不久的將來,又會遇到現在所面對的同樣的問題。而且隨著模塊的不斷的細化,應用系統的架構也會越來越復雜,整個系統很可能會出現失控的局面。

          這時候我們就必須要通過數據的水平切分的優勢,來解決這里所遇到的問題。而且,我們完全不必要在使用數據水平切分的時候,推倒之前進行數據垂直切分的成果,而是在其基礎上利用水平切分的優勢來避開垂直切分的弊端,解決系統復雜性不斷擴大的問題。而水平拆分的弊端(規則難以統一)也已經被之前的垂直切分解決掉了,讓水平拆分可以進行的得心應手。

          示例數據庫:

          假設在最開始,我們進行了數據的垂直切分,然而隨著業務的不斷增長,數據庫系統遇到了瓶頸,我們選擇重構數據庫集群的架構。如何重構?考慮到之前已經做好了數據的垂直切分,而且模塊結構清晰明確。而業務增長的勢頭越來越猛,即使現在進一步再次拆分模塊,也堅持不了太久。

          ==>選擇了在垂直切分的基礎上再進行水平拆分。

          ==>在經歷過垂直拆分后的各個數據庫集群中的每一個都只有一個功能模塊,而每個功能模塊中的所有表基本上都會與某個字段進行關聯。如用戶模塊全部都可以通過用戶ID進行切分,群組討論模塊則都通過群組ID來切分,相冊模塊則根據相冊ID來進切分,最后的事件通知信息表考慮到數據的時限性(僅僅只會訪問最近某個事件段的信息),則考慮按時間來切分。

          數據切分以及整合方案.

          數據庫中的數據在經過垂直和(或)水平切分被存放在不同的數據庫主機之后,應用系統面臨的最大問題就是如何來讓這些數據源得到較好的整合,其中存在兩種解決思路:

          • 在每個應用程序模塊中配置管理自己需要的一個(或者多個)數據源,直接訪問各個數據庫,在模塊內完成數據的整合;
          • 通過中間代理層來統一管理所有的數據源,后端數據庫集群對前端應用程序透明;

          第二種方案,雖然短期內需要付出的成本可能會相對更大一些,但是對整個系統的擴展性來說,是非常有幫助的。針對第二種方案,可以選擇的方法和思路有:

          1.利用MySQLProxy 實現數據切分及整合.

          可用來監視、分析或者傳輸他們之間的通訊信息。他的靈活性允許你最大限度的使用它,目前具備的功能主要有連接路由,Query分析,Query過濾和修改,負載均衡,以及基本的HA機制等。MySQLProxy 本身并不具有上述所有的這些功能,而是提供了實現上述功能的基礎。要實現這些功能,還需要通過我們自行編寫LUA腳本來實現。

          原理:MySQLProxy 實際上是在客戶端請求與MySQLServer 之間建立了一個連接池。所有客戶端請求都是發向MySQLProxy,然后經由MySQLProxy 進行相應的分析,判斷出是讀操作還是寫操作,分發至對應的MySQLServer 上。對于多節點Slave集群,也可以起做到負載均衡的效果。

          2.利用Amoeba實現數據切分及整合

          Amoeba是一個基于Java開發的,專注于解決分布式數據庫數據源整合Proxy程序的開源框架,Amoeba已經具有Query路由,Query過濾,讀寫分離,負載均衡以及HA機制等相關內容。Amoeba主要解決的以下幾個問題:

          • 數據切分后復雜數據源整合;
          • 提供數據切分規則并降低數據切分規則給數據庫帶來的影響;
          • 降低數據庫與客戶端的連接數;
          • 讀寫分離路由;

          AmoebaFor MySQL 主要是專門針對MySQL數據庫的解決方案,前端應用程序請求的協議以及后端連接的數據源數據庫都必須是MySQL。對于客戶端的任何應用程序來說,AmoebaForMySQL 和一個MySQL數據庫沒有什么區別,任何使用MySQL協議的客戶端請求,都可以被AmoebaFor MySQL 解析并進行相應的處理。

          Proxy程序常用的功能如讀寫分離,負載均衡等配置都在amoeba.xml中進行。Amoeba已經支持了實現數據的垂直切分和水平切分的自動路由,路由規則可以在rule.xml進行設置。

          3.利用HiveDB實現數據切分及整合


          HiveDB同樣是一個基于Java針對MySQL數據庫的提供數據切分及整合的開源框架,只是目前的HiveDB僅僅支持數據的水平切分。主要解決大數據量下數據庫的擴展性及數據的高性能訪問問題,同時支持數據的冗余及基本的HA機制。

          HiveDB的實現機制與MySQLProxy 和Amoeba有一定的差異,他并不是借助MySQL的Replication功能來實現數據的冗余,而是自行實現了數據冗余機制,而其底層主要是基于HibernateShards 來實現的數據切分工作。數據切分與整合中可能存在的問題

          引入分布式事務的問題?

          一旦數據進行切分被分別存放在多個MySQLServer中之后,不管我們的切分規則設計的多么的完美(實際上并不存在完美的切分規則),都可能造成之前的某些事務所涉及到的數據已經不在同一個MySQLServer 中了。

          ==>將一個跨多個數據庫的分布式事務分拆成多個僅處于單個數據庫上面的小事務,并通過應用程序來總控各個小事務。

          跨節點Join的問題?


          ==>先從一個節點取出數據,然后根據這些數據,再到另一個表中取數據.
          ==>使用Federated存儲引擎,問題是:乎如果遠端的表結構發生了變更,本地的表定義信息是不會跟著發生相應變化的。

          跨節點合并排序分頁問題?

          ==>Join本身涉及到的多個表之間的數據讀取一般都會存在一個順序關系。但是排序分頁就不太一樣了,排序分頁的數據源基本上可以說是一個表(或者一個結果集),本身并不存在一個順序關系,所以在從多個數據源取數據的過程是完全可以并行的。這樣,排序分頁數據的取數效率我們可以做的比跨庫Join更高,所以帶來的性能損失相對的要更小。  
          posted @ 2015-03-24 16:13 abin 閱讀(856) | 評論 (0)編輯 收藏

          前言

          有人反饋之前幾篇文章過于理論缺少實際操作細節,這篇文章就多一些可操作性的內容吧。

          注:這篇文章是以 MySQL 為背景,很多內容同時適用于其他關系型數據庫,需要有一些索引知識為基礎。

           

          優化目標

            1.減少 IO 次數

            IO永遠是數據庫最容易瓶頸的地方,這是由數據庫的職責所決定的,大部分數據庫操作中超過90%的時間都是 IO 操作所占用的,減少 IO 次數是 SQL 優化中需要第一優先考慮,當然,也是收效最明顯的優化手段。

            2.降低 CPU 計算

            除了 IO 瓶頸之外,SQL優化中需要考慮的就是 CPU 運算量的優化了。order by, group by,distinct … 都是消耗 CPU 的大戶(這些操作基本上都是 CPU 處理內存中的數據比較運算)。當我們的 IO 優化做到一定階段之后,降低 CPU 計算也就成為了我們 SQL 優化的重要目標

           

          優化方法

            改變 SQL 執行計劃

            明確了優化目標之后,我們需要確定達到我們目標的方法。對于 SQL 語句來說,達到上述2個目標的方法其實只有一個,那就是改變 SQL 的執行計劃,讓他盡量“少走彎路”,盡量通過各種“捷徑”來找到我們需要的數據,以達到 “減少 IO 次數” 和 “降低 CPU 計算” 的目標

           

          常見誤區

           

          1.count(1)和count(primary_key) 優于 count(*)

            很多人為了統計記錄條數,就使用 count(1) 和 count(primary_key) 而不是 count(*) ,他們認為這樣性能更好,其實這是一個誤區。對于有些場景,這樣做可能性能會更差,應為數據庫對 count(*) 計數操作做了一些特別的優化。

           

          2.count(column) 和 count(*) 是一樣的

            這個誤區甚至在很多的資深工程師或者是 DBA 中都普遍存在,很多人都會認為這是理所當然的。實際上,count(column) 和 count(*) 是一個完全不一樣的操作,所代表的意義也完全不一樣。

            count(column) 是表示結果集中有多少個column字段不為空的記錄

            count(*) 是表示整個結果集有多少條記錄

           

          3.select a,b from … 比 select a,b,c from … 可以讓數據庫訪問更少的數據量

            這個誤區主要存在于大量的開發人員中,主要原因是對數據庫的存儲原理不是太了解。

            實際上,大多數關系型數據庫都是按照行(row)的方式存儲,而數據存取操作都是以一個固定大小的IO單元(被稱作 block 或者 page)為單位,一般為4KB,8KB… 大多數時候,每個IO單元中存儲了多行,每行都是存儲了該行的所有字段(lob等特殊類型字段除外)。

            所以,我們是取一個字段還是多個字段,實際上數據庫在表中需要訪問的數據量其實是一樣的。

            當然,也有例外情況,那就是我們的這個查詢在索引中就可以完成,也就是說當只取 a,b兩個字段的時候,不需要回表,而c這個字段不在使用的索引中,需要回表取得其數據。在這樣的情況下,二者的IO量會有較大差異。

           

          4.order by 一定需要排序操作

            我們知道索引數據實際上是有序的,如果我們的需要的數據和某個索引的順序一致,而且我們的查詢又通過這個索引來執行,那么數據庫一般會省略排序操作,而直接將數據返回,因為數據庫知道數據已經滿足我們的排序需求了。

            實際上,利用索引來優化有排序需求的 SQL,是一個非常重要的優化手段

            延伸閱讀:MySQL ORDER BY 的實現分析,MySQL 中 GROUP BY 基本實現原理以及 MySQL DISTINCT 的基本實現原理這3篇文章中有更為深入的分析,尤其是第一篇

           

          5.執行計劃中有 filesort 就會進行磁盤文件排序

            有這個誤區其實并不能怪我們,而是因為 MySQL 開發者在用詞方面的問題。filesort 是我們在使用 explain 命令查看一條 SQL 的執行計劃的時候可能會看到在 “Extra” 一列顯示的信息。

            實際上,只要一條 SQL 語句需要進行排序操作,都會顯示“Using filesort”,這并不表示就會有文件排序操作。

           

          基本原則

          1.盡量少 join

            MySQL 的優勢在于簡單,但這在某些方面其實也是其劣勢。MySQL 優化器效率高,但是由于其統計信息的量有限,優化器工作過程出現偏差的可能性也就更多。對于復雜的多表 Join,一方面由于其優化器受限,再者在 Join 這方面所下的功夫還不夠,所以性能表現離 Oracle 等關系型數據庫前輩還是有一定距離。但如果是簡單的單表查詢,這一差距就會極小甚至在有些場景下要優于這些數據庫前輩。

           

          2.盡量少排序

            排序操作會消耗較多的 CPU 資源,所以減少排序可以在緩存命中率高等 IO 能力足夠的場景下會較大影響 SQL 的響應時間。

            對于MySQL來說,減少排序有多種辦法,比如:

            上面誤區中提到的通過利用索引來排序的方式進行優化

            減少參與排序的記錄條數

            非必要不對數據進行排序

            …

           

          3.盡量避免 select *

            很多人看到這一點后覺得比較難理解,上面不是在誤區中剛剛說 select 子句中字段的多少并不會影響到讀取的數據嗎?

            是的,大多數時候并不會影響到 IO 量,但是當我們還存在 order by 操作的時候,select 子句中的字段多少會在很大程度上影響到我們的排序效率,這一點可以通過我之前一篇介紹 MySQL ORDER BY 的實現分析的文章中有較為詳細的介紹。

            此外,上面誤區中不是也說了,只是大多數時候是不會影響到 IO 量,當我們的查詢結果僅僅只需要在索引中就能找到的時候,還是會極大減少 IO 量的。

           

          4.盡量用 join 代替子查詢

            雖然 Join 性能并不佳,但是和 MySQL 的子查詢比起來還是有非常大的性能優勢。MySQL 的子查詢執行計劃一直存在較大的問題,雖然這個問題已經存在多年,但是到目前已經發布的所有穩定版本中都普遍存在,一直沒有太大改善。雖然官方也在很早就承認這一問題,并且承諾盡快解決,但是至少到目前為止我們還沒有看到哪一個版本較好的解決了這一問題。

           

          5.盡量少 or

            當 where 子句中存在多個條件以“或”并存的時候,MySQL 的優化器并沒有很好的解決其執行計劃優化問題,再加上 MySQL 特有的 SQL 與 Storage 分層架構方式,造成了其性能比較低下,很多時候使用 union all 或者是union(必要的時候)的方式來代替“or”會得到更好的效果。

           

          6.盡量用 union all 代替 union

            union 和 union all 的差異主要是前者需要將兩個(或者多個)結果集合并后再進行唯一性過濾操作,這就會涉及到排序,增加大量的 CPU 運算,加大資源消耗及延遲。所以當我們可以確認不可能出現重復結果集或者不在乎重復結果集的時候,盡量使用 union all 而不是 union。

           

          7.盡量早過濾

            這一優化策略其實最常見于索引的優化設計中(將過濾性更好的字段放得更靠前)。

            在 SQL 編寫中同樣可以使用這一原則來優化一些 Join 的 SQL。比如我們在多個表進行分頁數據查詢的時候,我們最好是能夠在一個表上先過濾好數據分好頁,然后再用分好頁的結果集與另外的表 Join,這樣可以盡可能多的減少不必要的 IO 操作,大大節省 IO 操作所消耗的時間。

           

          8.避免類型轉換

            這里所說的“類型轉換”是指 where 子句中出現 column 字段的類型和傳入的參數類型不一致的時候發生的類型轉換:

            人為在column_name 上通過轉換函數進行轉換

            直接導致 MySQL(實際上其他數據庫也會有同樣的問題)無法使用索引,如果非要轉換,應該在傳入的參數上進行轉換

            由數據庫自己進行轉換

            如果我們傳入的數據類型和字段類型不一致,同時我們又沒有做任何類型轉換處理,MySQL 可能會自己對我們的數據進行類型轉換操作,也可能不進行處理而交由存儲引擎去處理,這樣一來,就會出現索引無法使用的情況而造成執行計劃問題。

           

          9.優先優化高并發的 SQL,而不是執行頻率低某些“大”SQL

            對于破壞性來說,高并發的 SQL 總是會比低頻率的來得大,因為高并發的 SQL 一旦出現問題,甚至不會給我們任何喘息的機會就會將系統壓跨。而對于一些雖然需要消耗大量 IO 而且響應很慢的 SQL,由于頻率低,即使遇到,最多就是讓整個系統響應慢一點,但至少可能撐一會兒,讓我們有緩沖的機會。

           

          10.從全局出發優化,而不是片面調整

            SQL 優化不能是單獨針對某一個進行,而應充分考慮系統中所有的 SQL,尤其是在通過調整索引優化 SQL 的執行計劃的時候,千萬不能顧此失彼,因小失大。

           

          11.盡可能對每一條運行在數據庫中的SQL進行 explain

            優化 SQL,需要做到心中有數,知道 SQL 的執行計劃才能判斷是否有優化余地,才能判斷是否存在執行計劃問題。在對數據庫中運行的 SQL 進行了一段時間的優化之后,很明顯的問題 SQL 可能已經很少了,大多都需要去發掘,這時候就需要進行大量的 explain 操作收集執行計劃,并判斷是否需要進行優化。

           

          原文地址:http://isky000.com/database/mysql-performance-tuning-sql

          posted @ 2015-03-24 15:51 abin 閱讀(374) | 評論 (0)編輯 收藏

          一,單一Bean

          • 裝載

          1. 實例化; 
          2. 設置屬性值; 
          3. 如果實現了BeanNameAware接口,調用setBeanName設置Bean的ID或者Name; 
          4. 如果實現BeanFactoryAware接口,調用setBeanFactory 設置BeanFactory; 
          5. 如果實現ApplicationContextAware,調用setApplicationContext設置ApplicationContext 
          6. 調用BeanPostProcessor的預先初始化方法; 
          7. 調用InitializingBean的afterPropertiesSet()方法; 
          8. 調用定制init-method方法; 
          9. 調用BeanPostProcessor的后初始化方法;

          • spring容器關閉

          1. 調用DisposableBean的destroy(); 
          2. 調用定制的destroy-method方法;

           

          二,多個Bean的先后順序

          • 優先加載BeanPostProcessor的實現Bean
          • 按Bean文件和Bean的定義順序按bean的裝載順序(即使加載多個spring文件時存在id覆蓋)
          • “設置屬性值”(第2步)時,遇到ref,則在“實例化”(第1步)之后先加載ref的id對應的bean
          • AbstractFactoryBean的子類,在第6步之后,會調用createInstance方法,之后會調用getObjectType方法
          • BeanFactoryUtils類也會改變Bean的加載順序
          posted @ 2015-03-23 22:10 abin 閱讀(633) | 評論 (0)編輯 收藏

          僅列出標題
          共50頁: First 上一頁 2 3 4 5 6 7 8 9 10 下一頁 Last 
          主站蜘蛛池模板: 庆阳市| 浦县| 海阳市| 包头市| 淄博市| 乌鲁木齐县| 泸溪县| 彰化县| 施秉县| 尚义县| 昭平县| 武山县| 满洲里市| 海安县| 南安市| 赤壁市| 汝南县| 黄梅县| 临江市| 柳河县| 沁阳市| 富阳市| 长阳| 娄底市| 金山区| 蓬溪县| 新泰市| 台南县| 安仁县| 佛学| 古蔺县| 兴隆县| 会同县| 青铜峡市| 马龙县| 庆城县| 乌鲁木齐县| 宜宾县| 锦屏县| 新巴尔虎左旗| 桂平市|