小總結:Redis緩存和數據庫以及Elasticsearch索引庫,JDBC

講講Redis

什麼是Redis?

redis是內存中的數據結構存儲系統,一個key-value類型的非關係型數據庫,可持久化的數據庫,相對於關係型數據庫(數據主要存在硬盤中),性能高,因此我們一般用redis來做緩存使用;並且redis支持豐富的數據類型,比較容易解決各種問題,因此redis可以用來作爲註冊中心,​數據庫、緩存和消息中間件。Redis的Value支持5種數據類型,string、hash、list、set、zset(sorted set);

String類型:一個key對應一個value

Hash類型:它的key是string類型,value又是一個map(key-value),適合存儲對象。

List類型:按照插入順序的字符串鏈表(雙向鏈表),主要命令是LPUSH和RPUSH,能夠支持反向查找和遍歷

Set類型:用哈希表類型的字符串序列,沒有順序,集合成員是唯一的,沒有重複數據,底層主要是由一個value永遠爲null的hashmap來實現的。

zset類型:和set類型基本一致,不過它會給每個元素關聯一個double類型的分數(score),這樣就可以爲成員排序,並且插入是有序的。

你還用過其他的緩存嗎?這些緩存有什麼區別?都在什麼場景下去用?

對於緩存瞭解過redis和memcache

Memcache和redis的區別:

數據支持的類型:redis不僅僅支持簡單的k/v類型的數據,同時還支持list、set、zset、hash等數據結構的存儲;memcache只支持簡單的k/v類型的數據,key和value都是string類型

可靠性:memcache不支持數據持久化,斷電或重啓後數據消失,但其穩定性是有保證的;redis支持數據持久化和數據恢復,允許單點故障,但是同時也會付出性能的代價

性能上:對於存儲大數據,memcache的性能要高於redis

應用場景:

Memcache:適合多讀少寫,大數據量的情況(一些官網的文章信息等)

Redis:適用於對讀寫效率要求高、數據處理業務複雜、安全性要求較高的系統

案例:分佈式系統,存在session之間的共享問題,因此在做單點登錄的時候,我們利用redis來模擬了session的共享,來存儲用戶的信息,實現不同系統的session共享;

對redis的持久化了解不?

redis的持久化方式有兩種:

RDB(半持久化方式):按照配置不定期的通過異步的方式、快照的形式直接把內存中的數據持久化到磁盤的一個dump.rdb文件(二進制的臨時文件)中,redis默認的持久化方式,它在配置文件(redis.conf)中。

優點:只包含一個文件,將一個單獨的文件轉移到其他存儲媒介上,對於文件備份、災難恢復而言,比較實用。

缺點:系統一旦在持久化策略之前出現宕機現象,此前沒有來得及持久化的數據將會產生丟失

RDB持久化配置:

Redis會將數據集的快照dump到dump.rdb文件中。此外,我們也可以通過配置文件來修改Redis服務器dump快照的頻率,在打開6379.conf文件之後,我們搜索save,可以看到下面的配置信息:

save 900 1              #在900秒(15分鐘)之後,如果至少有1個key發生變化,則dump內存快照。

save 300 10            #在300秒(5分鐘)之後,如果至少有10個key發生變化,則dump內存快照。

save 60 10000        #在60秒(1分鐘)之後,如果至少有10000個key發生變化,則dump內存快照。

AOF(全持久化的方式):把每一次數據變化都通過write()函數將你所執行的命令追加到一個appendonly.aof文件裏面,Redis默認是不支持這種全持久化方式的,需要在配置文件(redis.conf)中將appendonly no改成appendonly yes

優點:數據安全性高,對日誌文件的寫入操作採用的是append模式,因此在寫入過程中即使出現宕機問題,也不會破壞日誌文件中已經存在的內容;

缺點:對於數量相同的數據集來說,aof文件通常要比rdb文件大,因此rdb在恢復大數據集時的速度大於AOF;

AOF持久化配置:

在Redis的配置文件中存在三種同步方式,它們分別是:

appendfsync always     #每次有數據修改發生時都會都調用fsync刷新到aof文件,非常慢,但是安全;

appendfsync everysec  #每秒鐘都調用fsync刷新到aof文件中,很快,但是可能丟失一秒內的數據,推薦使用,兼顧了速度和安全;

appendfsync no          #不會自動同步到磁盤上,需要依靠OS(操作系統)進行刷新,效率快,但是安全性就比較差;

二種持久化方式區別:

AOF在運行效率上往往慢於RDB,每秒同步策略的效率是比較高的,同步禁用策略的效率和RDB一樣高效;

如果緩存數據安全性要求比較高的話,用aof這種持久化方式(比如項目中的購物車);

如果對於大數據集要求效率高的話,就可以使用默認的。而且這兩種持久化方式可以同時使用。  

做過redis的集羣嗎?你們做集羣的時候搭建了幾臺,都是怎麼搭建的?

Redis的數據是存放在內存中的,不適合存儲大數據,大數據存儲一般公司常用hadoop中的Hbase或者MogoDB。redis主要用來處理高併發的,用我們的項目來說,電商項目如果併發大的話,一臺單獨的redis是不能足夠支持我們的併發,這就需要我們擴展多臺設備協同合作,即用到集羣。

Redis搭建集羣的方式有多種,例如:客戶端分片、Twemproxy、Codis等,但是redis3.0之後就支持redis-cluster集羣,這種方式採用的是無中心結構,每個節點保存數據和整個集羣的狀態,每個節點都和其他所有節點連接。如果使用的話就用redis-cluster集羣。集羣這塊是公司運維搭建的,具體怎麼搭建不是太瞭解。

我們項目中redis集羣主要搭建了6臺,3主(爲了保證redis的投票機制)3從(高可用),每個主服務器都有一個從服務器,作爲備份機。所有的節點都通過PING-PONG機制彼此互相連接;客戶端與redis集羣連接,只需要連接集羣中的任何一個節點即可;Redis-cluster中內置了16384個哈希槽,Redis-cluster把所有的物理節點映射到【0-16383】slot上,負責維護。

redis有事務嗎?

Redis是有事務的,redis中的事務是一組命令的集合,這組命令要麼都執行,要不都不執行,保證一個事務中的命令依次執行而不被其他命令插入。redis的事務是不支持回滾操作的。redis事務的實現,需要用到MULTI(事務的開始)和EXEC(事務的結束)命令 ;

緩存穿透

緩存查詢一般都是通過key去查找value,如果不存在對應的value,就要去數據庫中查找。如果這個key對應的value在數據庫中也不存在,並且對該key併發請求很大,就會對數據庫產生很大的壓力,這就叫緩存穿透。

解決方案:

  • 對所有可能查詢的參數以hash形式存儲,在控制層先進行校驗,不符合則丟棄。
  • 將所有可能存在的數據哈希到一個足夠大的bitmap中,一個一定不存在的數據會被這個bitmap攔截掉,從而避免了對底層存儲系統的查詢壓力。
  • 如果一個查詢返回的數據爲空(不管是數 據不存在,還是系統故障),我們仍然把這個空結果進行緩存,但它的過期時間會很短,最長不超過五分鐘。

緩存雪崩

當緩存服務器重啓或者大量緩存集中在一段時間內失效,發生大量的緩存穿透,這樣在失效的瞬間對數據庫的訪問壓力就比較大,所有的查詢都落在數據庫上,造成了緩存雪崩。 這個沒有完美解決辦法,但可以分析用戶行爲,儘量讓失效時間點均勻分佈。大多數系統設計者考慮用加鎖或者隊列的方式保證緩存的單線程(進程)寫,從而避免失效時大量的併發請求落到底層存儲系統上。

解決方案:

  • 在緩存失效後,通過加鎖或者隊列來控制讀數據庫寫緩存的線程數量。比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待。
  • 可以通過緩存reload機制,預先去更新緩存,再即將發生大併發訪問前手動觸發加載緩存
  • 不同的key,設置不同的過期時間,讓緩存失效的時間點儘量均勻
  • 做二級緩存,或者雙緩存策略。A1爲原始緩存,A2爲拷貝緩存,A1失效時,可以訪問A2,A1緩存失效時間設置爲短期,A2設置爲長期。

redis的安全機制(你們公司redis的安全這方面怎麼考慮的?)

漏洞介紹:redis默認情況下,會綁定在bind 0.0.0.0:6379,這樣就會將redis的服務暴露到公網上,如果在沒有開啓認證的情況下,可以導致任意用戶在訪問目標服務器的情況下,未授權就可訪問redis以及讀取redis的數據,攻擊者就可以在未授權訪問redis的情況下可以利用redis的相關方法,成功在redis服務器上寫入公鑰,進而可以直接使用私鑰進行直接登錄目標主機;

解決方案:

  1. 禁止一些高危命令。修改redis.conf文件,用來禁止遠程修改DB文件地址,比如 rename-command FLUSHALL "" 、rename-command CONFIG"" 、rename-command EVAL “”等;
  2. 以低權限運行redis服務。爲redis服務創建單獨的用戶和根目錄,並且配置禁止登錄;
  3. 爲redis添加密碼驗證。修改redis.conf文件,添加requirepass mypassword;
  4. 禁止外網訪問redis。修改redis.conf文件,添加或修改 bind 127.0.0.1,使得redis服務只在當前主機使用;
  5. 做log監控,及時發現攻擊;

redis的哨兵機制(redis2.6以後出現的):

  • 監控:監控主數據庫和從數據庫是否正常運行;
  • 提醒:當被監控的某個redis出現問題的時候,哨兵可以通過API向管理員或者其他應用程序發送通知;
  • 自動故障遷移:主數據庫出現故障時,可以自動將從數據庫轉化爲主數據庫,實現自動切換;

具體的配置步驟參考的網上的文檔。要注意的是,如果master主服務器設置了密碼,記得在哨兵的配置文件(sentinel.conf)裏面配置訪問密碼

redis中對於生存時間的應用

  Redis中可以使用expire命令設置一個鍵的生存時間,到時間後redis會自動刪除;

  應用場景:

  1. 設置限制的優惠活動的信息;
  2. 一些及時需要更新的數據,積分排行榜;
  3. 手機驗證碼的時間;
  4. 限制網站訪客訪問頻率;

 

能講下redis的具體使用場景嗎?使用redis存儲長期不改變的數據完全可以使用也看靜態化,那麼你們當時是爲什麼會使用redis?

redis在項目中應用:

  • 主要應用在門戶網站首頁廣告信息的緩存。因爲門戶網站訪問量較大,將廣告緩存到redis中,可以降低數據庫訪問壓力,提高查詢性能。
  • 應用在用戶註冊驗證碼緩存。利用redis設置過期時間,當超過指定時間後,redis清理驗證碼,使過期的驗證碼無效。
  • 用在購物車模塊,用戶登陸系統後,添加的購物車數據需要保存到redis緩存中。

使用redis主要是減少系統數據庫訪問壓力。從緩存中查詢數據,也提高了查詢性能,挺高用戶體驗度。
 

Redis分佈式鎖理解

獲取鎖的時候,使用setnx加鎖,並使用expire命令爲鎖添加一個超時時間,超過該時間則自動釋放鎖,鎖的value值爲一個隨機生成的UUID,通過此在釋放鎖的時候進行判斷。

  • 獲取鎖的時候還設置一個獲取的超時時間,若超過這個時間則放棄獲取鎖。
  • 釋放鎖的時候,通過UUID判斷是不是該鎖,若是該鎖,則執行delete進行鎖釋放。
  • SETEX:如果 key 已經存在, SETEX 命令將覆寫舊值。
  • SETNX:若給定的 key 已經存在,則 SETNX 不做任何動作。

 

Redis怎麼設置過期的?

設置過期:this.redisTemplate.expire("max",tempTime,TimeUnit.SECONDS);

 

講到redis緩存的時候說不清楚

redis中項目中的使用場景:

  • 主要應用在門戶網站首頁廣告信息的緩存。因爲門戶網站訪問量較大,將廣告緩存到redis中,可以降低數據庫訪問壓力,提高查詢性能。
  • 應用在用戶註冊驗證碼緩存。利用redis設置過期時間,當超過指定時間後,redis清理驗證碼,使過期的驗證碼無效。
  • 用在購物車模塊,用戶登陸系統後,添加的購物車數據需要保存到redis緩存中。

技術角度分析:

  • Redis如何實現負載的?採用Hash槽來運算存儲值,使用CRC16算法取模運算,來保證負載問題。
  • Redis緩存穿透問題?將數據查詢出來如果沒有強制設置空值,並且設置過期時間,減少頻繁查詢數據庫。
  • 使用redis主要是減少系統數據庫訪問壓力。從緩存中查詢數據,也提高了查詢性能,挺高用戶體驗度。

 

redis中對一個key進行自增或者自減操作,它是原子性的嗎?

是原子性的。對於Redis而言,命令的原子性指的是:一個操作的不可以再分,操作要麼執行,要麼不執行。Redis的操作之所以是原子性的,是因爲Redis是單線程的。對Redis來說,執行get、set以及eval等API,都是一個一個的任務,這些任務都會由Redis的線程去負責執行,任務要麼執行成功,要麼執行失敗,這就是Redis的命令是原子性的原因。Redis本身提供的所有API都是原子操作,Redis中的事務其實是要保證批量操作的原子性。

 

項目添加Redis緩存後,持久化具體怎麼實現的。

  • RDB:保存存儲文件到磁盤;同步時間爲15分鐘,5分鐘,1分鐘一次,可能存在數據丟失問題。
  • AOF:保存命令文件到磁盤;安全性高,修改後立即同步或每秒同步一次。

上述兩種方式在我們的項目中都有使用到,在廣告輪播的功能中使用了redis緩存,先從redis中獲取數據,無數據後從數據庫中查詢後保存到redis中。採用默認的RDB方式。

 

怎麼提高redis緩存利用率

  • 從業務場景分析,預計會高頻率用到的數據預先存放到redis中,
  • 可以定時掃描命中率低的數據,可以直接從redis中清除。

 

Redis宕機之後,購物車中的數據如何處理?如何緩解mysql壓力?

用redis保存的*.rdb文件恢復即可。另外redis還有AOF功能,啓動時可以自動恢復到前一條查詢。這樣做在一定程度上減少數據丟失。但重啓redis會需要從關係型數據庫中讀取數據,增大mysql的壓力。依據實際情況,如果redis之前有主從複製,則可在其他節點redis上拿到數據。如果公司沒錢,則只能暫時限制客戶端訪問量,優先恢復redis數據。

 

Redis和mysql數據同步是先刪除redis還是先刪除mysql?

不管是先寫庫,再刪除緩存;還是先刪緩存,再寫庫,都有可能出現數據不一致的情況。因爲寫和讀是併發的,沒法保證順序,如果刪了緩存,還沒有來得及寫庫,另一個線程就來讀取,發現緩存爲空,則去數據庫中讀取數據寫入緩存,此時緩存中爲髒數據。如果先寫了庫,再刪除緩存前,寫庫的線程宕機了,沒有刪除掉緩存,則也會出現數據不一致情況。 如果是redis集羣,或者主從模式,寫主讀從,由於redis複製存在一定的時間延遲,也有可能導致數據不一致。這時候,考慮先刪除數據庫內容,再刪redis。因爲在庫存等實時數據都是直接在數據庫中讀取,從業務邏輯上來說,我們允許查詢時的數據緩存誤差,但是不允許結算時的數據存在誤差。

 

Redis中watch機制和原理

我們常用redis的watch和multi來處理一些涉及併發的操作,redis的watch+multi實際是一種樂觀鎖

watch命令描述:WATCH命令可以監控一個或多個鍵,一旦其中有一個鍵被修改(或刪除),之後的事務就不會執行。監控一直持續到EXEC命令(事務中的命令是在EXEC之後才執行的,所以在MULTI命令後可以修改WATCH監控的鍵值)

 

講講緩存的設計和優化,緩存和數據庫一致性同步解決方案

  • 降低後端負載:對於高消耗的SQL:join結果集、分組統計結果;對這些結果進行緩存。
  • 加速請求響應
  • 大量寫合併爲批量寫:如計數器先redis累加再批量寫入DB
  • 超時剔除:例如expire
  • 主動更新:開發控制生命週期(最終一致性,時間間隔比較短)
  • 緩存空對象
  • 布隆過濾器攔截
  • 命令本身的效率:例如sql優化,命令優化
  • 網絡次數:減少通信次數
  • 降低接入成本:長連/連接池,NIO等。
  • IO訪問合併

目的:要減少緩存重建次數、數據儘可能一致、減少潛在危險。
解決方案:
互斥鎖setex,setnx:

  • 如果 set(nx 和 ex) 結果爲 true,說明此時沒有其他線程重建緩存,那麼當前線程執行緩存構建邏輯。
  • 如果 setnx(nx 和 ex) 結果爲 false,說明此時已經有其他線程正在執行構建緩存的工作,那麼當前線程將休息指定時間 ( 例如這裏是 50 毫秒,取決於構建緩存的速度 ) 後,重新執行函數,直到獲取到數據。

永遠不過期:
熱點key,無非是併發特別大一級重建緩存時間比較長,如果直接設置過期時間,那麼時間到的時候,巨大的訪問量會壓迫到數據庫上,所以要給熱點key的val增加一個邏輯過期時間字段,併發訪問的時候,判斷這個邏輯字段的時間值是否大於當前時間,大於了說明要對緩存進行更新了,那麼這個時候,依然讓所有線程訪問老的緩存,因爲緩存並沒有設置過期,但是另開一個線程對緩存進行重構。等重構成功,即執行了redis set操作之後,所有的線程就可以訪問到重構後的緩存中的新的內容了

  • 從緩存層面來看,確實沒有設置過期時間,所以不會出現熱點 key 過期後產生的問題,也就是“物理”不過期。
  • 從功能層面來看,爲每個 value 設置一個邏輯過期時間,當發現超過邏輯過期時間後,會使用單獨的線程去構建緩存。

一致性問題:

  • 先刪除緩存,然後在更新數據庫,如果刪除緩存失敗,那就不要更新數據庫,如果說刪除緩存成功,而更新數據庫失敗,那查詢的時候只是從數據庫裏查了舊的數據而已,這樣就能保持數據庫與緩存的一致性。
  • 先去緩存裏看下有沒有數據,如果沒有,可以先去隊列裏看是否有相同數據在做更新,發現隊列裏有一個請求了,那麼就不要放新的操作進去了,用一個while(true)循環去查詢緩存,循環個200MS左右再次發送到隊列裏去,然後同步等待緩存更新完成。
     

爲什麼InnoDB支持事務而myisam不支持

MyISAM:這個是默認類型,它是基於傳統的ISAM類型,ISAM是Indexed Sequential Access Method (有索引的順序訪問方法) 的縮寫,它是存儲記錄和文件的標準方法.與其他存儲引擎比較,MyISAM具有檢查和修復表格的大多數工具. MyISAM表格可以被壓縮,而且它們支持全文搜索.它們不是事務安全的,而且也不支持外鍵。如果事物回滾將造成不完全回滾,不具有原子性。如果執行大量的SELECT,MyISAM是更好的選擇。

InnoDB:這種類型是事務安全的.它與BDB類型具有相同的特性,它們還支持外鍵.InnoDB表格速度很快.具有比BDB還豐富的特性,因此如果需要一個事務安全的存儲引擎,建議使用它.如果你的數據執行大量的INSERT或UPDATE,出於性能方面的考慮,應該使用InnoDB表
 

 

SQL語句中關於查詢語句的優化你們是怎麼做的?

  1. 應儘量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進行全表掃描。
  2. 對查詢進行優化,應儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。
  3. 應儘量避免在 where 子句中對字段進行 null 值判斷,否則將導致引擎放棄使用索引而進行全表掃描
  4. 儘量避免在 where 子句中使用 or 來連接條件,否則將導致引擎放棄使用索引而進行全表掃描
  5. in 和 not in 也要慎用,否則會導致全表掃描
  6. 應儘量避免在 where 子句中對字段進行表達式操作,這將導致引擎放棄使用索引而進行全表掃描。
  7. 應儘量避免在where子句中對字段進行函數操作,這將導致引擎放棄使用索引而進行全表掃描
  8. 不要在 where 子句中的“=”左邊進行函數、算術運算或其他表達式運算,否則系統將可能無法正確使用索引。
  9. 在使用索引字段作爲條件時,如果該索引是複合索引,那麼必須使用到該索引中的第一個字段作爲條件時才能保證系統使用該索引,否則該索引將不會被使 用,並且應儘可能的讓字段順序與索引順序相一致。
  10. 索引並不是越多越好,索引固然可以提高相應的 select 的效率,但同時也降低了 insert 及 update 的效率,因爲 insert 或 update 時有可能會重建索引,所以怎樣建索引需要慎重考慮,視具體情況而定。
  11. 儘可能的使用 varchar/nvarchar 代替 char/nchar ,因爲首先變長字段存儲空間小,可以節省存儲空間,其次對於查詢來說,在一個相對較小的字段內搜索效率顯然要高些。
  12. 任何地方都不要使用 select * from t ,用具體的字段列表代替“*”,不要返回用不到的任何字段。
  13. 使用連接(JOIN)來代替子查詢(Sub-Queries)
  14. 使用聯合(UNION)來代替手動創建的臨時表

 

MySQL索引使用限制

不要在列上進行運算

select * from users where YEAR(adddate)<2007; 
將在每個行上進行運算,這將導致索引失效而進行全表掃描,
因此我們可以改成select * from users where adddate<‘2007-01-01’;

like查詢是以%開頭不使用索引

    如果使用like。like “%aaa%” 不會使用索引而like “aaa%”可以使用索引。
    select * from users where name like '%aaa%'不會使用索引
    select * from users where name like 'aaa%'可以使用索引

使用短索引

例如,如果有一個CHAR(255)的列,如果在前10個或20個字符內,多數值是惟一的,
那麼就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節省磁盤空間和I/O操作。

索引不會包含NULL列,IS NULL /IS NOT NULL不使用索引

複合索引中如果有一列含有NULL值那麼這個組合索引都將失效,一般需要給默認值0或者 ' '字符串

 最左匹配,任何一個索引的最左前綴可以通過使用優化器來查找行

不按索引最左列開始查詢(多列索引) 例如:
index(‘c1’, ‘c2’, ‘c3’) ,
where ‘c2’ = ‘aaa’ 不使用索引,
where ‘c2’ = ‘aaa’ and ‘c3’ = ‘sss’ 不能使用索引。
where ‘c1’ = ‘aaa’ and ‘c2’ = ‘bbb’ 可以使用索引。
index('c1')靠最左可以使用索引。

多列索引,不是使用的第一部分,則不會使用索引

查詢中某個列有範圍查詢,則其右邊的所有列都無法使用查詢(多列查詢)。
where c1= ‘xxx’ and c2 like = ‘aa%’ and c3=’sss’ 
該查詢只會使用索引中的前兩列,c3將不能使用到索引,因爲like是範圍查詢。

檢索排序

一個查詢語句中,既有檢索又有排序並且是不同的字段,且這兩個列上都有單列索引(獨立索引),
那麼只有其中一個列用到索引,因爲查詢優化器在做檢索和排序中不能同時使用兩個不同的索引。

索引散列度

通過索引掃描的記錄超過了表總行數的30%(估計值),則查詢優化器認爲全表掃描的效率更高,所以會變成全表掃描查詢。

隱式轉換:如果列類型是字符串,那一定要在條件中將數據使用引號引用起來,否則不使用索引

隱式轉換導致的索引失效。比如,表的字段tu_mdn定義爲varchar(20),
但在查詢時把該字段作爲number類型當做where條件,這樣會導致索引失效. 
錯誤的例子:select * from test where tu_mdn=13333333333; 
正確的例子:select * from test where tu_mdn='13333333333’;

條件中有or

即使其中有條件帶索引也不會使用(這也是爲什麼儘量少用or的原因)
注意:要想使用or,又想讓索引生效,只能將or條件中的每個列都加上索引

使用全表掃描要比使用索引快,則不使用索引,數據唯一性差(一個字段的取值只有幾種時)的字段不要使用索引

比如性別,只有兩種可能數據。意味着索引的二叉樹級別少,多是平級。這樣的二叉樹查找無異於全表掃描

頻繁更新的字段不要使用索引

比如logincount登錄次數,頻繁變化導致索引也頻繁變化,增大數據庫工作量,降低效率

where 子句裏對索引列使用不等於(<>),使用索引效果一般,不使用索引

 

 

數據庫創建表的時候會有哪些考慮呢?

項目中使用的是MySQL數據庫,數據庫創建表時要考慮:

  • 大數據字段最好剝離出單獨的表,以便影響性能
  • 使用varchar,代替char,這是因爲varchar會動態分配長度,char指定爲20,即時你存儲字符“1”,它依然是20的長度
  • 給表建立主鍵,看到好多表沒主鍵,這在查詢和索引定義上將有一定的影響
  • 避免表字段運行爲null,如果不知道添加什麼值,建議設置默認值,特別int類型,比如默認值爲0,在索引查詢上,效率立顯。
  • 建立索引,聚集索引則意味着數據的物理存儲順序,最好在唯一的,非空的字段上建立,其它索引也不是越多越好,索引在查詢上優勢顯著,在頻繁更新數據的字段上建立聚集索引,後果很嚴重,插入更新相當忙。
  • 組合索引和單索引的建立,要考慮查詢實際和具體模式

 

有了解過大數據層面的分庫分表嗎?以及mysql的執行計劃嗎?

  • 分庫:通過Mycat結點來管理不同服務器上的數據庫,每個表最多存500萬條記錄
  • 分表:重直切割,水平切割

MySql提供了EXPLAIN語法用來進行查詢分析,在SQL語句前加一個"EXPLAIN"即可。mysql中的explain語法可以幫助我們改寫查詢,優化表的結構和索引的設置,從而最大地提高查詢效率。

 

有了解過數據庫中的表級鎖和行級鎖嗎?樂觀鎖和悲觀鎖你有哪些瞭解?

MySQL的鎖機制比較簡單,其最顯著的特點是不同的存儲引擎支持不同的鎖機制。比如,MyISAM和MEMORY存儲引擎採用的是表級鎖(table-level locking);InnoDB存儲引擎既支持行級鎖( row-level locking),也支持表級鎖,但默認情況下是採用行級鎖。

MySQL主要鎖的特性可大致歸納如下:

  • 表級鎖: 開銷小,加鎖快;不會出現死鎖(因爲MyISAM會一次性獲得SQL所需的全部鎖);鎖定粒度大,發生鎖衝突的概率最高,併發度最低。
  • 行級鎖: 開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度也最高。
  • 樂觀鎖:通過version版本字段來實現
  • 悲觀鎖:通過for update來實現

Sql層面:

一、悲觀鎖

  •     排它鎖,當事務在操作數據時把這部分數據進行鎖定,直到操作完畢後再解鎖,其他事務操作纔可操作該部分數據。這將防止其他進程讀取或修改表中的數據。
  •     實現:大多數情況下依靠數據庫的鎖機制實現

     一般使用 select ...for update 對所選擇的數據進行加鎖處理,例如select * from account where name=”Max” for update, 這條sql 語句鎖定了account 表中所有符合檢索條件(name=”Max”)的記錄。本次事務提交之前(事務提交時會釋放事務過程中的鎖),外界無法修改這些記錄。

二、樂觀鎖

  •     如果有人在你之前更新了,你的更新應當是被拒絕的,可以讓用戶重新操作。
  •     實現:大多數基於數據版本(Version)記錄機制實現

     具體可通過給表加一個版本號或時間戳字段實現,當讀取數據時,將version字段的值一同讀出,數據每更新一次,對此version值加一。當我們提交更新的時候,判斷當前版本信息與第一次取出來的版本值大小,如果數據庫表當前版本號與第一次取出來的version值相等,則予以更新,否則認爲是過期數據,拒絕更新,讓用戶重新操作。

代碼層面:

  • 悲觀鎖:一段執行邏輯加上悲觀鎖,不同線程同時執行時,只能有一個線程執行,其他的線程在入口處等待,直到鎖被釋放.
  • 樂觀鎖:一段執行邏輯加上樂觀鎖,不同線程同時執行時,可以同時進入執行,在最後更新數據的時候要檢查這些數據是否被其他線程修改了(版本和執行初是否相同),沒有修改則進行更新,否則放棄本次操作。
     

Mysql優化有沒有工具

三個MySQL性能測試工具:The MySQL Benchmark Suite、MySQL super-smack、MyBench。除了第一個爲MySQL性能測試工具,其他兩個都爲壓力測試工具。

 

你有了解mysql的隔離級別嗎?mysql默認的隔離級別是什麼?

數據庫事務的隔離級別有四種,隔離級別高的數據庫的可靠性高,但併發量低,而隔離級別低的數據庫可靠性低,但併發量高,系統開銷小。

  1. READ UNCIMMITTED(未提交讀)
  2. READ COMMITTED(提交讀)
  3. REPEATABLE READ(可重複讀)
  4. SERIALIZABLE(可串行化)

mysql默認的事務處理級別是'REPEATABLE-READ',也就是可重複讀。

 

怎樣進行數據庫性能調優

一:應用程序優化

 (1)把數據庫當作奢侈的資源看待,在確保功能的同時,儘可能少地動用數據庫資源。

 (2)不要直接執行完整的SQL 語法,儘量通過存儲過程實現數據庫操作。

 (3)客戶與服務器連接時,建立連接池,讓連接儘量得以重用,以避免時間與資源的損耗。

 (4)非到不得已,不要使用遊標結構,確實使用時,注意各種遊標的特性。

二:基本表設計優化

  (1)表設計遵循第三範式。在基於表驅動的信息管理系統中,基本表的設計規範是第三範式。

  (2)分割表。分割表可分爲水平分割表和垂直分割表兩種:水平分割是按照行將一個表分割爲多個表。

 (3)引入中間表。

: 數據庫索引優化

索引是建立在表上的一種數據組織,它能提高訪問表中一條或多條記錄的特定查詢效率。 

聚集索引

  一種索引,該索引中鍵值的邏輯順序決定了表中相應行的物理順序。 

  聚集索引確定表中數據的物理順序。

非聚集索引

  一種索引,該索引中索引的邏輯順序與磁盤上行的物理存儲順序不同.

 

MySQL存儲過程

SQL語句需要先編譯然後執行,而存儲過程(Stored Procedure)是一組爲了完成特定功能的SQL語句集,經編譯後存儲在數據庫中,用戶通過指定存儲過程的名字並給定參數(如果該存儲過程帶有參數)來調用執行它。

存儲過程是可編程的函數,在數據庫中創建並保存,可以由SQL語句和控制結構組成。當想要在不同的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是非常有用的。數據庫中的存儲過程可以看做是對編程中面向對象方法的模擬,它允許控制數據的訪問方式。

存儲過程的優點:

  1. 增強SQL語言的功能和靈活性:存儲過程可以用控制語句編寫,有很強的靈活性,可以完成複雜的判斷和較複雜的運算。
  2. 標準組件式編程:存儲過程被創建後,可以在程序中被多次調用,而不必重新編寫該存儲過程的SQL語句。而且數據庫專業人員可以隨時對存儲過程進行修改,對應用程序源代碼毫無影響。
  3. 較快的執行速度:如果某一操作包含大量的Transaction-SQL代碼或分別被多次執行,那麼存儲過程要比批處理的執行速度快很多。因爲存儲過程是預編譯的。在首次運行一個存儲過程時查詢,優化器對其進行分析優化,並且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。
  4. 減少網絡流量:針對同一個數據庫對象的操作(如查詢、修改),如果這一操作所涉及的Transaction-SQL語句被組織進存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大減少網絡流量並降低了網絡負載。
  5. 作爲一種安全機制來充分利用:通過對執行某一存儲過程的權限進行限制,能夠實現對相應的數據的訪問權限的限制,避免了非授權用戶對數據的訪問,保證了數據的安全。

MySQL存儲過程的創建

語法:

CREATE PROCEDURE  過程名([[IN|OUT|INOUT] 參數名 數據類型[,[IN|OUT|INOUT] 參數名 數據類型…]]) [特性 ...] 過程體

DELIMITER //
  CREATE PROCEDURE myproc(OUT s int)
    BEGIN
      SELECT COUNT(*) INTO s FROM students;
    END
    //
DELIMITER ;

分隔符:MySQL默認以";"爲分隔符,如果沒有聲明分割符,則編譯器會把存儲過程當成SQL語句進行處理,因此編譯過程會報錯,所以要事先用“DELIMITER //”聲明當前段分隔符,讓編譯器把兩個"//"之間的內容當做存儲過程的代碼,不會執行這些碼;“DELIMITER ;”的意爲把分隔符還原。

參數:存儲過程根據需要可能會有輸入、輸出、輸入輸出參數,如果有多個參數用","分割開。MySQL存儲過程的參數用在存儲過程的定義,共有三種參數類型,IN,OUT,INOUT:

  • IN參數的值必須在調用存儲過程時指定,在存儲過程中修改該參數的值不能被返回,爲默認值
  • OUT:該值可在存儲過程內部被改變,並可返回
  •  INOUT:調用時指定,並且可被改變和返回

過程體:過程體的開始與結束使用BEGIN與END進行標識。
 

 

怎麼實現數據量大、 併發量高的搜索

創建Elasticsearch/solr索引庫,數據量特別大時採用Elasticsearch/solr分佈式集羣。

 

ES的用途

ES在系統中主要完成商品搜索功能,提高搜索性能。

 

講講Elasticsearch全文搜索:

簡單介紹一個Elasticsearch?

ElasticSearch是一個基於Lucene的搜索服務器。通過HTTP使用JSON進行數據索引,用於分佈式全文檢索,解決人們對於搜索的衆多要求。

lucene與elasticsearch(solr)有什麼區別?

lucene只是一個提供全文搜索功能類庫的核心工具包,而真正使用它還需要一個完善的服務框架搭建起來的應用。好比lucene是類似於jdk,而搜索引擎軟件就是tomcat 的。elasticsearch和solr,這兩款都是基於lucene的搭建的,可以獨立部署啓動的搜索引擎服務軟件。

基本概念:

cluster集羣

整個elasticsearch 默認就是集羣狀態,整個集羣是一份完整、互備的數據。

node節點

集羣中的一個節點,一般只一個進程就是一個node

shard分片

分片,即使是一個節點中的數據也會通過hash算法,分成多個片存放,默認是5片。

index邏輯數據庫

相當於rdbms的database, 對於用戶來說是一個邏輯數據庫,雖然物理上會被分多個shard存放,也可能存放在多個node中。

type

類似於rdbms的table,但是與其說像table,其實更像面向對象中的class , 同一Json的格式的數據集合。

document

類似於rdbms的 row、面向對象裏的object

field

相當於字段、屬性

與MySQL對比

利用kibana學習 elasticsearch restful api (DSL)

Kibana 是一個開源分析和可視化平臺,可視化操作 Elasticsearch 。Kibana可以用來搜索,查看和與存儲在 Elasticsearch 索引中的數據進行交互。可以輕鬆地進行高級數據分析,並可在各種圖表,表格和地圖中顯示數據。

ES提供了基於JSON的query DSL查詢語言

es中保存的數據結構

public class  Movie {

 String id;

     String name;

     Double doubanScore;

     List<Actor> actorList;

}

 

public class Actor{

String id;

String name;

}

這兩個對象如果放在關係型數據庫保存,會被拆成2張表,但是elasticsearch是用一個json來表示一個document。

所以它保存到es中應該是:

{

  “id”:”1”,

  “name”:”operation red sea”,

  “doubanScore”:”8.5”,

  “actorList”:[  

{“id”:”1”,”name”:”zhangyi”},

{“id”:”2”,”name”:”haiqing”},

{“id”:”3”,”name”:”zhanghanyu”}

]

}

es 的java 客戶端的選擇

目前市面上有兩類客戶端

  • 一種是TransportClient 爲代表的ES原生客戶端,不能執行原生dsl語句必須使用它的Java api方法。
  • 一種是以Rest Api爲主的missing client,最典型的就是jest。 這種客戶端可以直接使用dsl語句拼成的字符串,直接傳給服務端,然後返回json字符串再解析。

兩種方式各有優劣,但是最近elasticsearch官網,宣佈計劃在7.0以後的版本中廢除TransportClient。以RestClient爲主。在官方的RestClient 基礎上,進行了簡單包裝的Jest客戶端,就成了首選,而且該客戶端也與springboot完美集成。

中文分詞

elasticsearch本身自帶的中文分詞,就是單純把中文一個字一個字的分開,根本沒有詞彙的概念。

問題:

  • es大量的寫操作會影響es 性能,因爲es需要更新索引,而且es不是內存數據庫,會做相應的io操作。
  • 而且修改某一個值,在高併發情況下會有衝突,造成更新丟失,需要加鎖,而es的樂觀鎖會惡化性能問題。

解決思路:

用redis做精確計數器,redis是內存數據庫讀寫性能都非常快,利用redis的原子性的自增可以解決併發寫操作。redis每計100次數(可以被100整除)我們就更新一次es ,這樣寫操作就被稀釋了100倍,這個倍數可以根據業務情況靈活設定。

增量同步索引庫

推薦使用MQ(RabbitMQ)

原理:使用MQ做增量同步,即當修改數據之後就將此數據發送至MQ,由MQ將此數據同步到ES上

 

ES索引中使用了IK分詞器,你們項目中使用到了分詞器的哪種工作模式?

IK分詞器,基本可分爲兩種模式,一種爲smart模式,一種爲非smart模式。

例如:張三說的確實在理
smart模式的下分詞結果爲:
張三 | 說的 | 確實 | 在理
而非smart模式下的分詞結果爲:
張三 | 三 | 說的 | 的確 | 的 | 確實 | 實在 | 在理
可見非smart模式所做的就是將能夠分出來的詞全部輸出;smart模式下,IK分詞器則會根據內在方法輸出一個認爲最合理的分詞結果,這就涉及到了歧義判斷。

項目中採用的是smart模塊分詞的。

 

怎麼分詞

使用第三方的分詞器IKAnalyzer,會按照中國人用此習慣自動分詞。

 

 ES高亮不能顯示的問題

前臺使用angularJS加載搜索結果,但是發現高亮不能展示。

問題原因:

angularJS底層使用ajax,異步加載高亮信息返回給頁面後,頁面沒有刷新,就直接顯示返回的數據。此時會把所有的數據作爲普通的文本數據進行加載。因此就沒有高亮的效果。

解決方案:

使用angularJS過濾器過濾文本數據,此時angularJS過濾器把html文本數據解析爲瀏覽器能識別的html標籤。高亮就能展示了。

 

簡單介紹一下Es全文檢索在整個系統中的應用,在更新索引庫的同時會產生索引碎片,這個碎片是如何處理的?

根據商品的名稱,分類,品牌等屬性來創建索引進行商品搜索。

更新索引庫時會先刪除索引,然後再重建。而對於刪除聚集索引,則會導致對應的非聚集索引重建兩次(刪除時重建,建立時再重建).直接刪除碎片。

 

JDBC的理解

JDBC(Java DataBase Connectivity,java數據庫連接)是一種用於執行SQL語句的Java API,可以爲多種關係數據庫提供統一訪問,它由一組用Java語言編寫的類和接口組成。JDBC提供了一種基準,據此可以構建更高級的工具和接口,使數據庫開發人員能夠編寫數據庫應用程序

有了JDBC,向各種關係數據發送SQL語句就是一件很容易的事。換言之,有了JDBC API,就不必爲訪問Sybase數據庫專門寫一個程序,爲訪問Oracle數據庫又專門寫一個程序,或爲訪問Informix數據庫又編寫另一個程序等等,程序員只需用JDBC API寫一個程序就夠了,它可向相應數據庫發送SQL調用。
 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章