面試 Q&A (二)

java中的基本數據類型

參考:php

基本數據類型 字節 範圍 默認值
byte 8-bit 1個字節 -128 ~ 127 0
short 16-bit 2個字節 -32768 ~ 32767 0
int 32-bit 4個字節 -2^31 ~ 2^31 - 1 0
long 64-bit 8個字節 -2^63 ~ 2^63 -1 0L
float 32-bit 4個字節 0.0f
double 64-bit 8個字節 0.0d
boolean 1-bit false
char 16-bit unicode字符 '\u0000'~'\uffff' '\u0000'

char = '中文'能夠經過編譯麼?

能夠。html

public class primitivetype {
  public static void main(String[] args) {
    char i = '中';
    System.out.println(i);
  }
}
複製代碼

能夠運行輸出'中'前端

Java中的一個char採用的是Unicode編碼集,佔用兩個字節,而一箇中文字符也是兩個字節,所以Java中的char是能夠表示一箇中文字符的。java

可是在C/C++中因爲採用的字符編碼集是ASCII,只有一個字節,所以是沒辦法表示一箇中文字符的。node

Java中的char是否能夠存儲一箇中文字符之理解字符字節以及編碼集mysql

char幾個字節?存儲中文的char是幾個字節?

java中char類型固定佔2個字節。(注:char類型也能夠存儲一個漢字)。web

以utf8爲例,utf8是一個變長編碼標準,能夠以1~4個字節表示一個字符,而中文佔3個字節,ascII字符佔1個字節。算法

那麼爲何咱們在java裏面能夠用一個char來表示一箇中文呢?spring

由於java是以unicode做爲編碼方式的。unicode是一個定長的編碼標準,每一個字符都是2個字節,也就是1個char類型的空間。sql

在編譯時會把utf8的中文字符轉換成對應的unicode來進行傳輸運算。

String採用一種更靈活的方式進行存儲。在String中,一個英文字符佔1個字節,而中文字符根據編碼的不一樣所佔字節數也不一樣。在UTF-8編碼下,一箇中文字符佔3個字節;而使用GBK編碼時一箇中文字符佔2個字節。測試代碼以下

中文並不必定是佔兩個字節的,具體佔多少字節是跟具體的編碼方式相關的。 好比說:GB23十二、GBK、GB18030 編碼是佔用兩個字節的,可是 UTF-8 編碼的話至少須要佔用三個字節。

解釋一下MVC 以及 MVC Spring

MVC

MVC模式是軟件工程中的一種軟件架構模式,把軟件系統分爲三個基本部分:模型、視圖和控制器。

mvc是一種建構網站的方法或思想,設計理念。mvc不是框架,而框架是基於mvc思想。

在早期java web,主要使用jsp + java bean模式,jsp與java bean產生嚴重耦合。出現了前端後端相互依賴的問題。

因而出現了servlet + jsp + java bean。 servlet是controller jsp是view 各自java bean 是model 對於後端來講,因爲控制器和模型層的分離使得許多代碼能夠重用。 mvc的經典框架 struts1/struts2和做爲模型層的hibernate紛紛出現。

  • springmvc中傳統的模型層被拆分紅業務層service和數據訪問層dao。
  • 在service下能夠經過spring的聲明式事務操做數據訪問層,而在業務層還容許訪問nosql。
  • Spring MVC經過一套MVC註解,讓POJO普通java類成爲處理請求的控制器,而無需實現任何接口。
  • 支持REST風格的URL請求
  • 採用鬆散耦合可插拔組件結構,比其餘MVC框架更具擴展性和靈活性

spring mvc組件和流程圖

執行原理

  1. spring mvc將全部的請求都提交給DispatcherServlet,它會委託應用系統的其餘模塊負責對請求 進行真正的處理工做。
  2. DispatcherServlet查詢一個或多個HandlerMapping,找處處理請求的Controller.
  3. DispatcherServlet請請求提交到目標Controller
  4. Controller進行業務邏輯處理後,會返回一個ModelAndView
  5. Dispathcher查詢一個或多個ViewResolver視圖解析器,找到ModelAndView對象指定的視圖對象
  6. 視圖對象負責渲染返回給客戶端。

  • 用戶發起請求到前端控制器(Controller)
  • 前端控制器沒有處理業務邏輯的能力,須要找到具體的模型對象處理(Handler),處處理器映射器(HandlerMapping)中查找Handler對象(Model)。
  • HandlerMapping返回執行鏈,包含了2部份內容: ① Handler對象、② 攔截器數組
  • 前端處理器經過處理器適配器包裝後執行Handler對象。
  • 處理業務邏輯。
  • Handler處理完業務邏輯,返回ModelAndView對象,其中view是視圖名稱,不是真正的視圖對象。
  • 將ModelAndView返回給前端控制器。
  • 視圖解析器(ViewResolver)返回真正的視圖對象(View)。
  • (此時前端控制器中既有視圖又有Model對象數據)前端控制器根據模型數據和視圖對象,進行視圖渲染。
  • 返回渲染後的視圖(html/json/xml)返回。
  • 給用戶產生響應。

在瀏覽器輸入url發生了什麼?

假如輸入maps.google.com

1. 瀏覽器會檢查dns記錄緩存,找到url對應的ip地址

dns:domain name system 保存域名和鏈接的ip地址,每個url都有惟一的ip地址。

爲了找到dns記錄,瀏覽器會依次檢查如下4種緩存

  • 檢查瀏覽器緩存,瀏覽器爲您之前訪問過的網站維護一個固按期限的DNS記錄存儲庫。所以,它是第一個運行DNS查詢的地方。
  • 瀏覽器檢查系統緩存。若是在瀏覽器緩存中找不到,瀏覽器將向底層計算機OS發出系統調用(即Windows上的gethostname)以獲取記錄,由於OS還維護DNS記錄的緩存。
  • 檢查路由器緩存。若是在你的電腦上找不到的話,瀏覽器就會與維護本身的DNS記錄緩存的路由器進行通訊。
  • 它檢查ISP緩存。若是全部的步驟都失敗了,瀏覽器將轉移到ISP。您的ISP維護它本身的DNS服務器,它包含一個DNS記錄的緩存,瀏覽器將會檢查找到您請求的URL的最後但願。

Internet Service Provider,簡稱ISP

2. 若是請求的URL不在緩存中,ISP的DNS服務器將發起一個DNS查詢,以查找託管maps.google.com的服務器的IP地址。

爲了讓個人計算機鏈接到託管maps.google.com的服務器,我須要maps.google.com的IP地址。DNS查詢的目的是在internet上搜索多個DNS服務器,直到找到網站的正確IP地址。這種類型的搜索被稱爲遞歸搜索,由於搜索將在DNS服務器和DNS服務器之間重複進行,直到找到咱們須要的IP地址,或者返回一個錯誤響應說沒法找到它爲止。

在這種狀況下,咱們將把ISP的DNS服務器稱爲DNS遞歸器,它的職責是經過詢問internet上的其餘DNS服務器來找到想要的域名的正確IP地址。其餘DNS服務器稱爲名稱服務器,由於它們基於網站域名的域架構執行DNS搜索。

3. 瀏覽器啓動與服務器的TCP鏈接

HTTP協議即超文本傳送協議(Hypertext Transfer Protocol ),是Web聯網的基礎,也是手機聯網經常使用的協議之一,HTTP協議是創建在TCP協議之上的一種應用。

一旦瀏覽器接收到正確的IP地址,它將與匹配IP地址以傳輸信息的服務器創建TCP鏈接。三次握手。

爲了在您的計算機(客戶端)和服務器之間傳輸數據包,創建一個TCP鏈接很是重要。這個鏈接是經過一個叫作TCP/IP三方握手的過程創建的。這是一個三個步驟,其中客戶端和服務器交換SYN(同步)和ACK(確認)消息來創建鏈接。

爲了保證服務端能收接受到客戶端的信息並能作出正確的應答而進行前兩次(第一次和第二次)握手,爲了保證客戶端可以接收到服務端的信息並能作出正確的應答而進行後兩次(第二次和第三次)握手。

4. 瀏覽器發送http請求

好比get請求 localhost:8080

Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Cookie: JSESSIONID=8051806AE26B8CAB93BA03AC32A2191E; JSESSIONID=63AB1FE24ECF5F0930743468B802818B
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
複製代碼

5. 服務器處理請求並返回響應

該服務器包含一個web服務器(好比apache)。接收來自瀏覽器的請求並將其傳遞給請求處理程序以讀取和生成響應。請求處理程序是一個程序(用php等編寫)用於讀取請求、其頭部和cookies,以檢查所請求的內容,並在須要時更新服務器上的信息。而後它將以特定的格式(JSON、XML、HTML)組裝響應。

6. 服務器發送一個HTTP響應。

服務器響應包含您請求的web頁面、狀態代碼、壓縮類型(內容編碼)、如何緩存頁面(緩存控制)、要設置的任何cookie、隱私信息等。

HTTP/1.1 200 
Content-Type: text/html;charset=UTF-8
Content-Language: zh-CN
Content-Length: 97
Date: Wed, 04 Jul 2018 08:04:54 GMT
複製代碼

狀態碼:

  • 1xx表明一條信息
  • 2xx說明訪問成功
  • 3xx將客戶重定向到其餘url
  • 4xx客戶端發生錯誤
  • 5xx服務端發生錯誤 狀態碼詳細

7. 瀏覽器顯示html內容

瀏覽器分階段顯示HTML內容。首先,它將呈現裸骨HTML骨架。而後,它將檢查HTML標記併發出GET請求,請求web頁面上的其餘元素,如圖像、CSS樣式表、JavaScript文件等。這些靜態文件被瀏覽器緩存,這樣下次訪問頁面時就沒必要再取回它們了。最後,你會看到網頁出如今你的瀏覽器上。

HashMap如何實現的?

  • hashmap是基於哈希表即散列表的。

  • hashmap經過hashCode方法計算hash值,hash值是經過key對象來計算。hash值用來找到存儲Entry的正確位置。

  • hashmap使用equals方法來查找在get()時要檢索的鍵的值,並在put()時查找該鍵是否已經存在。

  • 衝突意味着有多個鍵擁有一樣的hash值,在這種狀況下entry對象將會存儲在了同一個linkedlist裏。

    HashMap在java中使用內部 Node<K,V>來存儲映射。HashMap基於散列算法,並在鍵上使用hashCode()和equals()方法進行get和put操做。

    HashMap使用單個鏈表來存儲元素,這些元素稱爲bucket。當咱們調用put方法時,將使用key的hashCode來肯定存儲映射的bucket。

    一旦肯定了bucket,就使用hashCode檢查是否已經有一個具備相同hashCode的鍵。若是存在一個具備相同hashCode的現有鍵,則在key上使用equals()方法。若是equals返回true,那麼value將被覆蓋,不然將對這個單獨連接的list bucket建立一個新的映射。若是沒有具備相同hashCode的鍵,則將映射插入到bucket中。

    hashmap 有一個表

    **
    * The table, resized as necessary. Length MUST Always be a power of two.
    */
    
       transient Node<K,V>[] table;
    複製代碼

static class Node<K,V> implements Map.Entry<K,V> {
      final int hash;
      final K key;
      V value;
      Node<K,V> next;

      Node(int hash, K key, V value, Node<K,V> next) {
          this.hash = hash;
          this.key = key;
          this.value = value;
          this.next = next;
      }

      public final K getKey() { return key; }
      public final V getValue() { return value; }
      public final String toString() { return key + "=" + value; }

      public final int hashCode() {
          return Objects.hashCode(key) ^ Objects.hashCode(value);
      }

      public final V setValue(V newValue) {
          V oldValue = value;
          value = newValue;
          return oldValue;
      }

      public final boolean equals(Object o) {
          if (o == this)
              return true;
          if (o instanceof Map.Entry) {
              Map.Entry<?,?> e = (Map.Entry<?,?>)o;
              if (Objects.equals(key, e.getKey()) &&
                  Objects.equals(value, e.getValue()))
                  return true;
          }
          return false;
      }
  }
複製代碼

put方法,注意鏈表中是紅黑樹的實現

TreeNode節點,這個類有很是多的方法
static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
        TreeNode<K,V> parent;  // red-black tree links
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;
        TreeNode(int hash, K key, V val, Node<K,V> next) {
            super(hash, key, val, next);
        }
}
複製代碼
public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

    /** * Implements Map.put and related methods * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */
    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }
複製代碼

GC過程,GC是在何時,對什麼東西,作了什麼事情?

gc須要完成的3件事情

  • 何時回收?
  • 哪些內存須要回收?
  • 如何回收?

對堆進行回收以前首先要肯定對象之中哪些還「存活」,哪些「死去」。

  1. 引用計數算法

  2. 可達性分析算法 這個算法的基本思路就是經過一系列的稱爲「GC Roots」的對象做爲起始點,從這些節點開始向下搜索,搜索所走過的路徑稱爲引用鏈(Reference Chain),當一個對象到GC Roots沒有任何引用鏈相連(用圖論的話來講,就是從GC Roots到這個對象不可達)時,則證實此對象是不可用的。

    在java中,可做爲GC Roots的對象包括如下幾種:

    • 虛擬機棧(棧幀中的本地變量表)中引用的對象
    • 方法區中類靜態屬性引用的對象
    • 方法區中常量引用的對象
    • 本地方法棧中JNI(Native方法)引用的對象。

強引用,軟引用,弱引用,虛引用

  • 強引用 :指在程序代碼之中廣泛存在的,相似Object obj=new Object()這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象。
  • 軟引用 :還有用但並不是必需的對象。在系統將要發生內存溢出異常以前,將會把這些對象列進回收範圍之中進行第二次回收。若是此次回收尚未足夠的內存,纔會拋出內存溢出異常。
  • 弱引用 :非必需對象,當垃圾收集器工做時,不管當前內存是否足夠,都會回收掉只被弱引用關聯的對象。
  • 虛引用 :幽靈引用或幻影引用,一個對象是否有虛引用的存在,徹底不會對其生存時間構成影響,也沒法經過虛引用來取得一個對象實例。爲一個對象設置虛引用關聯的惟一目的就是能在這個對象被收集器回收時收到一個系統通知。

回收方法區(永久代)

永久代的垃圾回收主要回收兩部分

  • 廢棄常量
  • 無用的類:該類全部的實例都已經被回收,也就是java堆中不存在該類的任何實例,加載該類的ClassLoader已經被回收,該類對應的java.lang.Class對象沒有在任何地方被引用,沒法在任何地方經過反射訪問該類的方法。
  • 在大量使用反射、動態代理、CGLib等ByteCode框架、動態生成JSP以及OSGi這類頻繁自定義ClassLoader的場景都須要虛擬機具有類卸載的功能,以保證永久代不會溢出。

垃圾收集算法

1. 標記-清除算法

最基礎的收集算法,"mark-sweep"標記-清除算法。

算法分爲「標記」和「清除」兩個階段:首先標記出全部須要回收的對象,在標記完成後統一回收全部被標記的對象,它的標記過程其實在前一節講述對象標記斷定時已經介紹過了。之因此說它是最基礎的收集算法,是由於後續的收集算法都是基於這種思路並對其不足進行改進而獲得的。

它的主要不足有兩個:一個是效率問題,標記和清除兩個過程的效率都不高;另外一個是空間問題,標記清除以後會產生大量不連續的內存碎片,空間碎片太多可能會致使之後在程序運行過程當中須要分配較大對象時,沒法找到足夠的連續內存而不得不提早觸發另外一次垃圾收集動做。

2. 複製算法

爲了解決效率問題,一種稱爲「複製」(Copying)的收集算法出現了,它將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活着的對象複製到另一塊上面,而後再把已使用過的內存空間一次清理掉。這樣使得每次都是對整個半區進行內存回收,內存分配時也就不用考慮內存碎片等複雜狀況,只要移動堆頂指針,按順序分配內存便可,實現簡單,運行高效。只是這種算法的代價是將內存縮小爲了原來的一半,未免過高了一點。

新生代中的對象98%是「朝生夕死」的,因此並不須要按照1:1的比例來劃份內存空間,而是將內存分爲一塊較大的Eden空間兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。當回收時,將Eden和Survivor中還存活着的對象一次性地複製到另一塊Survivor空間上,最後清理掉Eden和剛纔用過的Survivor空間。HotSpot虛擬機默認Eden和Survivor的大小比例是8:1,也就是每次新生代中可用內存空間爲整個新生代容量的90%(80%+10%),只有10%的內存會被「浪費」。固然,98%的對象可回收只是通常場景下的數據,咱們沒有辦法保證每次回收都只有很少於10%的對象存活,當Survivor空間不夠用時,須要依賴其餘內存(這裏指老年代)進行分配擔保(Handle Promotion)。

內存的分配擔保就比如咱們去銀行借款,若是咱們信譽很好,在98%的狀況下都能按時償還,因而銀行可能會默認咱們下一次也能按時按量地償還貸款,只須要有一個擔保人能保證若是我不能還款時,能夠從他的帳戶扣錢,那銀行就認爲沒有風險了。內存的分配擔保也同樣,若是另一塊Survivor空間沒有足夠空間存放上一次新生代收集下來的存活對象時,這些對象將直接經過分配擔保機制進入老年代。

3. 標記-整理法

標記過程仍然與「標記-清除」算法同樣,但後續步驟不是直接對可回收對象進行清理,而是讓全部存活的對象都向一端移動,而後直接清理掉端邊界之外的內存。

4. 分代收集算法Generational Collection

只是根據對象存活週期的不一樣將內存劃分爲幾塊。通常是把Java堆分爲新生代和老年代,這樣就能夠根據各個年代的特色採用最適當的收集算法。

在新生代中,每次垃圾收集時都發現有大批對象死去,只有少許存活,那就選用複製算法,只須要付出少許存活對象的複製成本就能夠完成收集。

而老年代中由於對象存活率高、沒有額外空間對它進行分配擔保,就必須使用「標記—清理」或者「標記—整理」算法來進行回收。

垃圾收集器

若是說收集算法是內存回收的方法論,那麼垃圾收集器就是內存回收的具體實現

Minor GC 和 Full GC

  • 新生代GC(Minor GC):指發生在新生代的垃圾收集動做,由於Java對象大多都具有朝生夕滅的特性,因此Minor GC很是頻繁,通常回收速度也比較快。具體原理見上一篇文章。
  • 老年代GC(Major GC / Full GC):指發生在老年代的GC,出現了Major GC,常常會伴隨至少一次的Minor GC(但非絕對的,在Parallel Scavenge收集器的收集策略裏就有直接進行Major GC的策略選擇過程)。Major GC的速度通常會比Minor GC慢10倍以上。

內存分配與回收策略

  • 對象優先在Eden分配 大多數狀況下,對象在新生代Eden區分配,等eden區沒有足夠空間進行分配,虛擬機將會發起一次Minor GC
  • 大對象直接進入老年代 所謂大對象是指,須要大量連續內存空間的java對象,最典型的就是那種很長的字符串和數組。
  • 長期存活的對象將進入老年代 爲了肯定哪些是老年代,虛擬機給每一個對象定義了一個對象年齡計數器。對象在Survivor區中每熬過一次Minor GC年齡就增長1.
  • 空間分配擔保 在發生Minor GC以前,虛擬機會先檢查老年代最大可用的連續空間是否大於新生代全部對象總空間,若是這個條件成立,那麼Minor GC能夠確保是安全的。若是不成立,則虛擬機會查看HandlePromotionFailure設置值是否容許擔保失敗。若是容許,那麼會繼續檢查老年代最大可用的連續空間是否大於歷次晉升到老年代對象的平均大小,若是大於,將嘗試着進行一次Minor GC,儘管此次Minor GC是有風險的;若是小於,或者HandlePromotionFailure設置不容許冒險,那這時也要改成進行一次Full GC

何時發生回收?

eden滿了minor gc,升到老年代的對象大於老年代剩餘空間full gc,或者小於時被HandlePromotionFailure參數強制full gc;gc與非gc時間耗時超過了GCTimeRatio的限制引起OOM,調優諸如經過NewRatio控制新生代老年代比例,經過MaxTenuringThreshold控制進入老年前生存次數等

參考:icyfenix.iteye.com/blog/715301

數據庫慢查詢

慢sql特色 1 數據庫CPU負載高。通常是查詢語句中有不少計算邏輯,致使數據庫cpu負載。 2 IO負載高致使服務器卡住。這個通常和全表查詢沒索引有關係。 3 查詢語句正常,索引正常可是仍是慢。若是表面上索引正常,可是查詢慢,須要看看是否索引沒有生效。

打開MySQL的慢查詢日誌來進一步定位問題。mysql提供了慢查詢日誌,日誌會記錄全部執行時間超過long_query_time的sql

要開啓日誌,須要在MySQL的配置文件的mysqlld項下配置慢查詢日誌開啓。

有些SQL雖然出如今慢查詢日誌中,但未必是其自己的性能問題,多是由於鎖等待,服務器壓力高等等。

須要分析SQL語句真實的執行計劃,而不是看從新執行一遍SQL時,花費了多少時間,由自帶的慢查詢日誌或者開源的慢查詢系統定位到具體的出問題的SQL,而後使用Explain工具來逐步調優,瞭解 MySQL 在執行這條數據時的一些細節,好比是否進行了優化、是否使用了索引等等。基於 Explain 的返回結果咱們就能夠根據 MySQL 的執行細節進一步分析是否應該優化搜索、怎樣優化索引。

總結

  1. 打開慢日誌查詢,肯定是否有SQL語句佔用了過多資源,若是是,在不改變業務原意的前提下,對insert、group by、order by、join等語句進行優化。
  2. 考慮調整MySQL的系統參數:innodb_buffer_pool_size、innodb_log_file_size、table_cache等。
  3. 肯定是不是由於高併發引發行鎖的超時問題。
  4. 若是數據量過大,須要考慮進一步的分庫分表。

數據庫inner join,left outer join,right outer join

兩個表,customers,orders

customers

cust_id cust_name cust_address cust_city cust_state cust_zip cust_country cust_contact cust_email
10001 Coyote Inc. 200 Maple Lane Detroit MI 44444 USA Y Lee ylee@coyote.com
10002 Mouse House 333 Fromage Lane Columbus OH 43333 USA Jerry Mouse NULL
10003 Wascals 1 Sunny Place Muncie IN 42222 USA Jim Jones rabbit@wascally.com
10004 Yosemite Place 829 Riverside Drive Phoenix AZ 88888 USA Y Sam sam@yosemite.com
10005 E Fudd 4545 53rd Street Chicago IL 54545 USA E Fudd NULL

內部聯結

orders

order_num order_date cust_id
20005 2005-09-01 00:00:00 10001
20006 2005-09-12 00:00:00 10003
20007 2005-09-30 00:00:00 10004
20008 2005-10-03 00:00:00 10005
20009 2005-10-08 00:00:00 10001
SELECT customers.cust_id,orders.order_num FROM customers INNER JOIN orders ON customers.cust_id = orders.cust_id;
複製代碼
cust_id order_num
10001 20005
10001 20009
10003 20006
10004 20007
10005 20008

外部聯結

SELECT customers.cust_id,orders.order_num FROM customers LEFT OUTER JOIN orders ON customers.cust_id = orders.cust_id
複製代碼
cust_id order_num
10001 20005
10001 20009
10002 NULL
10003 20006
10004 20007
10005 20008
SELECT customers.cust_id,orders.order_num FROM customers RIGHT OUTER JOIN orders ON customers.cust_id = orders.cust_id
複製代碼
cust_id order_num
10001 20005
10001 20009
10003 20006
10004 20007
10005 20008

在使用OUTER JOIN語法時,必須使用RIGHTLEFT關鍵字 指定包括其全部行的表(RIGHT指出的是OUTER JOIN右邊的表,而LEFT指出的是OUTER JOIN左邊的表)。上面的例子使用LEFT OUTER JOINFROM子句的左邊表(customers表)中選擇全部行。爲了從右邊的表中選擇全部行,應該使用RIGHT OUTER JOIN.

解釋一下索引

當表的數據量比較大時,查詢操做會比較耗時。創建索引是加快查詢速度的有效手段。數據庫索引相似於圖書後面的索引,能快速定位到須要查詢的內容。

數據庫索引有多種類型,常見索引包括順序文件上的索引b+樹索引哈希索引位圖索引全文索引

在mysql中,存儲引擎先在索引中找到對應值,而後根據匹配的索引記錄找到對應的數據行。

mysql先在索引上按值進行查找,而後返回全部包含該值的數據行。

索引能夠包含一個或多個列的值。若是索引包含多個列,那麼列的順序也十分重要,由於mysql只能高效地使用索引的最左前綴列。

索引可讓服務器快速定位到表的指定位置 索引的優勢:

  1. 索引大大減小了服務器須要掃描的數據量
  2. 索引能夠幫助服務器避免排序和臨時表
  3. 索引可讓隨機I/O變成順序I/O

數據庫優化

數據庫優化總結

  • 選取最適用的字段屬性
  • 使用join來代替子查詢
  • 使用聯合union來代替手動建立的臨時表
  • 使用事務
  • 鎖定表

schema模式與數據類型優化

mysql支持的數據類型很是多,選擇正確的數據類型對於得到高性能相當重要。無論存儲哪一種類型的數據,下面幾個簡單的原則都有助於做出更好選擇。

  • 更小,通常狀況下儘可能使用能夠正確存儲數據的最小數據類型。
  • 簡單就好,簡單數據類型須要更少的cpu週期。
  • 儘可能避免null

使用索引

索引的代價:1.須要佔硬盤空間 2.一旦插入新的數據,須要從新建索引 高性能索引策略

  • 獨立的列,獨立的列」是指索引列不能是表達式的一部分,也不能是函數的參數
  • 前綴索引和索引選擇性
  • 多列索引
  • 選擇合適的索引列順序
  • 聚簇索引

查詢性能優化

優化數據訪問

  • 是否向數據庫請求了不須要的數據
    • mysql是否掃描額外的記錄
      • 查詢消耗:響應時間,掃描的行數,返回的行數

重構查詢的方式

優化服務器設置

操做系統和硬件優化

層次遍歷

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null){
            return res;
        }
        Queue<TreeNode> qp = new LinkedList<>();
        qp.offer(root);
        
        while(!qp.isEmpty()){
            List<Integer> level = new ArrayList<>();
            TreeNode node = null;
            int lenL = qp.size();
            for(int i = 0; i < lenL; i++){
                node = qp.poll();
                level.add(node.val);
                if(node.left != null){
                    qp.offer(node.left);
                }
                
                if(node.right != null){
                    qp.offer(node.right);
                }
            }
            res.add(level);
        }
        return res;
    }
}
複製代碼
相關文章
相關標籤/搜索