MySQL面試匯總

一、MyISAM 與 InnoDB 的區別

MyISAM 是 MySQL 的默認數據庫引擎(5.5版之前)。雖然性能極佳,而且提供了大量的特性,包括全文索引、壓縮、空間函數等,但 MyISAM 不支持事務和行級鎖,而且最大的缺陷就是崩潰后無法安全恢復。不過,5.5 版本之后,MySQL 引入了 InnoDB (事務性數據庫引擎),MySQL5.5 版本后默認的存儲引擎為 InnoDB。大多數時候使用的都是 InnoDB 存儲引擎,但是在某些情況下使用 MyISAM 也是合適的比如讀密集的情況下。兩者的對比:

1??InnoDB 支持事務,而 MyISAM 不支持事務。InnoDB 的 AUTOCOMMIT 默認是打開的,即每條 SQL 語句會默認被封裝成一個事務,自動提交,這樣會影響速度,最好把多條 SQL 語句顯示放在 begin 和 commit 之間,組成一個事務去提交。
2??InnoDB 支持行級鎖(row-level locking)(默認)和表級鎖,而 MyISAM 只支持表級鎖(table-level locking)。即 MyISAM 同一個表上的讀寫是互斥的,MyISAM 并發讀寫時如果等待隊列中既有讀請求又有寫請求,默認寫請求的優先級高,即使讀請求先到,所以 MyISAM 不適合于有大量查詢和修改并存的情況,那樣查詢進程會長時間阻塞。因為 MyISAM 是鎖表,所以某項讀操作比較耗時會使其他寫進程餓死。
3??InnoDB 支持外鍵,而 MyISAM 不支持。
4??InnoDB的主鍵范圍更大,最大是 MyISAM 的 2 倍。
5??InnoDB 不支持全文索引,而 MyISAM 支持。全文索引是指對 char、varchar 和 text 中的每個詞(停用詞除外)建立倒排序索引。MyISAM 的全文索引其實沒啥用,因為它不支持中文分詞,必須由使用者分詞后加入空格再寫到數據表里,而且少于 4 個漢字的詞會和停用詞一樣被忽略掉。
6??InnoDB 支持 MVCC(數據庫的多版本并發控制),而 MyISAM 不支持。
應對高并發事務,MVCC 比單純的加鎖更高效;MVCC 只在 READ COMMITTED 和 REPEATABLE READ 兩個隔離級別下工作;MVCC 可以使用樂觀鎖和悲觀鎖來實現。各數據庫 MVCC 實現并不統一。
7??MyISAM 支持 GIS 數據,InnoDB 不支持。即 MyISAM 支持以下空間數據對象:Point、Line、Polygon 和 Surface 等。
8??沒有 where 的 count(*) 使用 MyISAM 要比 InnoDB 快得多。因為 MyISAM 內置了一個計數器,count(*) 時它直接從計數器中讀,而 InnoDB 必須掃描全表。所以在 InnoDB 上執行 count(*) 時一般要伴隨 where,且 where 中要包含主鍵以外的索引列。為什么“主鍵以外”?因為 InnoDB 中 primary index 是和 raw data 存放在一起的,而 secondary index 則是單獨存放,然后有個指針指向 primary key。所以只是 count(*) 的話使用 secondary index 掃描更快,而 primary key 則主要在掃描索引同時要返回 raw data 時的作用較大。

《MySQL高性能》上面有一句話這樣寫到:不要輕易相信“MyISAM比InnoDB快”之類的經驗之談,這個結論往往不是絕對的。在很多已知場景中,InnoDB 的速度都可以讓 MyISAM 望塵莫及,尤其是用到了聚簇索引,或者需要訪問的數據都可以放入內存的應用。一般情況下選擇 InnoDB 都是沒有問題的,但是某事情況下并不在乎可擴展能力和并發能力,也不需要事務支持,也不在乎崩潰后的安全恢復問題的話,選擇 MyISAM 也是一個不錯的選擇。但是一般情況下,都是需要考慮到這些問題的。

補充:
1??InnoDB 引擎的4大特性:
插入緩沖(insert buffer)、二次寫(double write)、自適應哈希索引(ahi)、預讀(read ahead)

二、MySQL 中的 varchar 與 char

1??varchar 與 char 的區別
char 是一種固定長度的類型,varchar 則是一種可變長度的類型。盡可能的使用 varchar 代替 char,因為首先變長字段存儲空間小,節省存儲空間,其次對于查詢來說,在一個相對較小的字段內搜索效率顯然要高些。
2??varchar(50) 中 50 的含義
最多存放 50 個字符。varchar(50) 和 varchar(200) 存儲 hello 所占空間一樣,但后者在排序時會消耗更多內存,因為 order by col 采用 fixed_length 計算 col 長度(memory引擎也一樣)。varchar(50) 這里的 50 限制的是儲存字符的個數,字符不分貴賤(不分中文、英文、數字...)
3??int(20)中 20 的含義
顯示字符的長度。但要加參數的,最大為 255,比如它是記錄行數的 id,插入 10 筆資料,它就顯示 00000000001 ~~~00000000010。當字符的位數超過 20,它也只顯示 20 位,如果沒有加那個讓它未滿 20 位就前面加 0 的參數,它不會在前面加 0。20 表示最大顯示寬度為 20,但仍占 4 字節存儲,存儲范圍不變。MySQL 這么設計對大多數應用沒有意義,只是規定一些工具用來顯示字符的個數。int(1) 和 int(20) 存儲和計算均一樣。

三、MySQL 的復制原理以及流程

  1. 在 Slave 服務器上執行 start slave 命令開啟主從復制開關,開始進行主從復制。

  2. 此時,Slave服務器的IO線程會通過在master上已經授權的復制用戶權限請求連接master服務器,并請求從執行binlog日志文件的指定位置(日志文件名和位置就是在配置主從復制服務時執行change master命令指定的)之后開始發送binlog日志內容。

3.根據Slave服務器的IO線程請求的信息分批讀取指定binlog日志文件指定位置之后的binlog日志信息,然后返回給Slave端的IO線程。返回的信息中除了binlog日志內容外,還有在master服務器端記錄的新的binlog文件名稱,以及在新的binlog中的下一個指定更新位置。

  1. 當Slave服務器的IO線程獲取到Master服務器上IO線程發送的日志內容、日志文件及位置點后,會將binlog日志內容依次寫到Slave端自身的Relay Log(即中繼日志)文件(MySQL-relay-bin.xxx)的最末端,并將新的binlog文件名和位置記錄到master-info文件中,以便下一次讀取master端新binlog日志時能告訴Master服務器從新binlog日志的指定文件及位置開始讀取新的binlog日志內容。

  2. Slave服務器端的SQL線程會實時檢測本地Relay Log 中IO線程新增的日志內容,然后及時把Relay LOG 文件中的內容解析成sql語句,并在自身Slave服務器上按解析SQL語句的位置順序執行應用這樣sql語句,并在relay-log.info中記錄當前應用中繼日志的文件名和位置點。

基本原理流程,3 個線程以及之間的關聯;

主:binlog 線程——記錄下所有改變了數據庫數據的語句,放進 master 上的 binlog 中。
從:io 線程——在使用 start slave 之后,負責從 master 上拉取 binlog 內容,放進自己的 relay log 中。
從:sql 執行線程——執行 relay log 中的語句。

四、Innodb的事務與日志的實現方式

1??事務的四種隔離級別

讀未提交(RU)
讀已提交(RC)
可重復讀(RR)
串行

2??日志分類:

  1. 錯誤日志:記錄出錯信息,也記錄一些警告信息或者正確的信息。
  2. 查詢日志:記錄所有對數據庫請求的信息,不論這些請求是否得到了正確的執行。
  3. 慢查詢日志:設置一個閾值,將運行時間超過該值的所有 SQL 語句都記錄到慢查詢的日志文件中。
  4. 二進制日志:記錄對數據庫執行更改的所有操作。
  5. 中繼日志:中繼日志也是二進制日志,用來給slave 庫恢復
  6. 事務日志:重做日志redo和回滾日志undo

3??事務是如何通過日志來實現的,說得越深入越好。

事務日志是通過redo和innodb的存儲引擎日志緩沖(Innodb log buffer)來實現的,當開始一個事務的時候,會記錄該事務的lsn(log sequence number)號;當事務執行時,會往InnoDB存儲引擎的日志的日志緩存里面插入事務日志;當事務提交時,必須將存儲引擎的日志緩沖寫入磁盤(通過innodb_flush_log_at_trx_commit來控制),也就是寫數據前,需要先寫日志。這種方式稱為“預寫日志方式”。

五、MySQL binlog的幾種日志錄入格式以及區別

1??Statement:每一條會修改數據的sql都會記錄在binlog中。

優點:不需要記錄每一行的變化,減少了binlog日志量,節約了IO,提高性能。(相比row能節約多少性能 與日志量,這個取決于應用的SQL情況,正常同一條記錄修改或者插入row格式所產生的日志量還小于Statement產生的日志量,但是考慮到如果帶條 件的update操作,以及整表刪除,alter表等操作,ROW格式會產生大量日志,因此在考慮是否使用ROW格式日志時應該跟據應用的實際情況,其所 產生的日志量會增加多少,以及帶來的IO性能問題。)

缺點:由于記錄的只是執行語句,為了這些語句能在slave上正確運行,因此還必須記錄每條語句在執行的時候的 一些相關信息,以保證所有語句能在slave得到和在master端執行時候相同 的結果。另外mysql 的復制,像一些特定函數功能,slave可與master上要保持一致會有很多相關問題(如sleep()函數, last_insert_id(),以及user-defined functions(udf)會出現問題).

使用以下函數的語句也無法被復制:

LOAD_FILE()
UUID()
USER()
FOUND_ROWS()
SYSDATE() (除非啟動時啟用了 --sysdate-is-now 選項)
同時在INSERT …SELECT 會產生比 RBR 更多的行級鎖

2??Row:不記錄sql語句上下文相關信息,僅保存哪條記錄被修改。

優點: binlog中可以不記錄執行的sql語句的上下文相關的信息,僅需要記錄那一條記錄被修改成什么了。所以rowlevel的日志內容會非常清楚的記錄下 每一行數據修改的細節。而且不會出現某些特定情況下的存儲過程,或function,以及trigger的調用和觸發無法被正確復制的問題

缺點:所有的執行的語句當記錄到日志中的時候,都將以每行記錄的修改來記錄,這樣可能會產生大量的日志內容,比 如一條update語句,修改多條記錄,則binlog中每一條修改都會有記錄,這樣造成binlog日志量會很大,特別是當執行alter table之類的語句的時候,由于表結構修改,每條記錄都發生改變,那么該表每一條記錄都會記錄到日志中。

3??Mixedlevel:是以上兩種level的混合使用,一般的語句修改使用statment格式保存binlog,如一些函數,statement無法完成主從復制的操作,則 采用row格式保存binlog,MySQL會根據執行的每一條具體的sql語句來區分對待記錄的日志形式,也就是在Statement和Row之間選擇 一種.新版本的MySQL中隊row level模式也被做了優化,并不是所有的修改都會以row level來記錄,像遇到表結構變更的時候就會以statement模式來記錄。至于update或者delete等修改數據的語句,還是會記錄所有行的變更。

六、MySQL 數據庫 cpu 飆升到 500% 怎么處理

1??列出所有進程 show processlist,觀察所有進程,多秒沒有狀態變化的(干掉)
2??查看超時日志或者錯誤日志 (一般是查詢以及大批量的插入會導致cpu與i/o上漲,當然不排除網絡突然中斷,導致一個請求服務器只接受到一半,比如 where 子句或分頁子句沒有發送)

七、500臺db,在最快時間之內重啟

可以使用批量 ssh 工具 pssh 來對需要重啟的機器執行重啟命令。 也可以使用 salt(前提是客戶端有安裝 salt)或者 ansible(ansible 只需要 ssh 免登通了就行)等多線程工具同時操作多臺服務器。

八、Innodb的讀寫參數優化

1??讀取參數:
global buffer pool以及 local buffer;
2??寫入參數:
innodb_flush_log_at_trx_commit
innodb_buffer_pool_size
3??與IO相關的參數:
innodb_write_io_threads = 8
innodb_read_io_threads = 8
innodb_thread_concurrency = 0
4??緩存參數以及緩存的適用場景。
query cache/query_cache_type
并不是所有表都適合使用query cache。造成query cache失效的原因主要是相應的table發生了變更

第一個:讀操作多的話看看比例,簡單來說,如果是用戶清單表,或者說是數據比例比較固定,比如說商品列表,是可以打開的,前提是這些庫比較集中,數據庫中的實務比較小。

第二個:我們“行騙”的時候,比如說競標的時候壓測,把query cache打開,還是能收到qps激增的效果,當然前提示前端的連接池什么的都配置一樣。大部分情況下如果寫入的居多,訪問量并不多,那么就不要打開,例如社交網站的,10%的人產生內容,其余的90%都在消費,打開還是效果很好的,但是你如果是qq消息,或者聊天,那就很要命。

第三個:小網站或者沒有高并發的無所謂,高并發下,會看到很多 qcache 鎖等待,所以一般高并發下,不建議打開query cache

九、如何監控數據庫?慢日志是怎么查詢的?

監控的工具有很多,例如zabbix,lepus

十、怎么做主從一致性校驗?

主從一致性校驗有多種工具。例如checksum、mysqldiff、pt-table-checksum等

十一、數據庫如何支持emoji表情?

如果是utf8字符集的話,需要升級至utf8_mb4方可支持。

十二、表中有大字段X(例如:text類型),且字段X不會經常更新,以讀為為主,請問

拆帶來的問題:連接消耗 + 存儲拆分空間;不拆可能帶來的問題:查詢性能;

1??如果能容忍拆分帶來的空間問題,拆的話最好和經常要查詢的表的主鍵在物理結構上放置在一起(分區) 順序IO,減少連接消耗,最后這是一個文本列再加上一個全文索引來盡量抵消連接消耗。
2??如果能容忍不拆分帶來的查詢性能損失的話:上面的方案在某個極致條件下肯定會出現問題,那么不拆就是最好的選擇。

十三、MySQL中InnoDB的行鎖是通過加在什么上實現的?為什么?

InnoDB是基于索引來完成行鎖。

例: select * from tab_with_index where id = 1 for update;

for update 可以根據條件來完成行鎖鎖定,并且 id 是有索引鍵的列,如果 id 不是索引鍵,那么InnoDB將完成表鎖,并發將無從談起。

十四、一個6億的表a,一個3億的表b,通過外鍵tid關聯,如何最快的查詢出滿足條件的第50000到第50200中的這200條數據記錄

1??如果A表tid是自增長,并且是連續的,B表的ID為索引

select * from a,b where a.tid = b.id and a.tid>500000 limit 200;

2??如果A表的tid不是連續的,那么就需要使用覆蓋索引。tid要么是主鍵,要么是輔助索引,B表ID也需要有索引。

select * from b, (select tid from a limit 50000,200) a where b.id = a .tid;

十五、使用索引查詢一定能提高查詢的性能嗎?

通常,通過索引查詢數據比全表掃描要快。但是也必須注意到它的代價。索引需要空間來存儲,也需要定期維護,每當有記錄在表中增減或索引列被修改時,索引本身也會被修改。這意味著每條記錄的INSERT、DELETE、UPDATE將為此多付出4、5次的磁盤I/O。因為索引需要額外的存儲空間和處理,那些不必要的索引反而會使查詢反應時間變慢。使用索引查詢不一定能提高查詢性能,索引范圍查詢(INDEX RANGE SCAN)適用于兩種情況:
①基于一個范圍的檢索,一般查詢返回結果集小于表中記錄數的30%。
②基于非唯一性索引的檢索。

十六、簡單說一說drop、delete與truncate的區別

SQL中的drop、delete、truncate都表示刪除,但是三者有一些差別:
①delete和truncate只刪除表的數據不刪除表的結構。
②速度一般來說:drop > truncate > delete
③delete語句是DML,這個操作會放到rollback segement中,事務提交之后才生效。
④如果有相應的trigger,執行的時候將被觸發。truncate、drop是DDL,操作立即生效。原數據不放到rollback segment中,不能回滾。操作不觸發trigger。

十七、drop、delete與truncate分別在什么場景之下使用?

①不再需要一張表的時候,用drop。
②想刪除部分數據行時候,用delete,并且帶上where子句。
③保留表而刪除所有數據的時候用truncate。

十八、超鍵、候選鍵、主鍵、外鍵分別是什么?

①超鍵:在關系中能唯一標識元組的屬性集稱為關系模式的超鍵。一個屬性可以為作為一個超鍵,多個屬性組合在一起也可以作為一個超鍵。超鍵包含候選鍵和主鍵。
②候選鍵:是最小超鍵,即沒有冗余元素的超鍵。
③主鍵:數據庫表中對儲存數據對象予以唯一和完整標識的數據列或屬性的組合。一個數據列只能有一個主鍵,且主鍵的取值不能缺失,即不能為空值(Null)。
④外鍵:在一個表中存在的另一個表的主鍵稱此表的外鍵。

十九、什么是視圖?以及視圖的使用場景有哪些?

①視圖是一種虛擬的表,具有和物理表相同的功能。可以對視圖進行增,改,查,操作,試圖通常是有一個表或者多個表的行或列的子集。對視圖的修改不影響基本表。它使得我們獲取數據更容易,相比多表查詢。
②只暴露部分字段給訪問者,所以就建一個虛表,就是視圖。
③查詢的數據來源于不同的表,而查詢者希望以統一的方式查詢,這樣也可以建立一個視圖,把多個表查詢結果聯合起來,查詢者只需要直接從視圖中獲取數據,不必考慮數據來源于不同表所帶來的差異

二十、數據庫三范式

  1. 第一范式(1NF):數據庫表中的字段都是單一屬性,不可再分的。這個單一屬性由基本類型構成,包括整型、實數、字符型、邏輯型、日期型等。
  2. 第二范式(2NF):數據庫表中不存在非關鍵字段對任一候選關鍵字段的部分函數依賴(即不存在組合關鍵字中的某些字段決定非關鍵字段的情況),也即所有非關鍵字段都完全依賴于任意一組候選關鍵字。
  3. 第三范式(3NF):在第二范式的基礎上,數據表中如果不存在非關鍵字段對任一候選關鍵字段的傳遞函數依賴則符合第三范式。所謂傳遞函數依賴,指的是如果存在“A→B→C”的決定關系,則 C 傳遞函數依賴于 A。因此,滿足第三范式的數據庫表應該不存在如下依賴關系: 關鍵字段 → 非關鍵字段 x → 非關鍵字段y

二十一、數據庫的樂觀鎖和悲觀鎖是什么?

數據庫管理系統(DBMS)中的并發控制的任務是確保在多個事務同時存取數據庫中同一數據時不破壞事務的隔離性和統一性以及數據庫的統一性。樂觀并發控制(樂觀鎖)和悲觀并發控制(悲觀鎖)是并發控制主要采用的技術手段。

悲觀鎖:假定會發生并發沖突,屏蔽一切可能違反數據完整性的操作。
樂觀鎖:假設不會發生并發沖突,只在提交操作時檢查是否違反數據完整性。

二十二、常考 sql 書寫

1??查出銷量前十的記錄:
Oracle

過度設計:
select id,col from(
select rownum rn,uo.* from (select * from table order by sales desc) uo
where rownum<=10 ) ua;
最優:
select * from table order by sales desc where rownum<=10;  

MySQL

select * from table order by sales desc limit 10;  

2??查找表中多余的重復記錄,重復記錄是根據單個字段(UserId)來判斷

select * from table
where UserId in 
(select  UserId  from  table group  by  UserId  having  count(UserId) > 1)

3??刪除表中多余的重復記錄,重復記錄是根據單個字段(UserId)來判斷,只留有rowid最小的記錄

delete from table
where UserId in 
(select  UserId from table group  by  UserId having  count(UserId) > 1)
and rowid not in 
(select min(rowid) from  table group by UserId having count(UserId)>1)

4??查找表中多余的重復記錄(多個字段)

select * from table a
where (a.UserId,a.seq) in  
(select UserId,seq from table group by UserId,seq  having count(*) > 1)

5??刪除表中多余的重復記錄(多個字段),只留有rowid最小的記錄

delete from table a
where (a.UserId,a.seq) in  
(select UserId,seq from table group by UserId,seq having count(*) > 1)
and rowid not in 
(select min(rowid) from table group by UserId,seq having count(*)>1)

6??查找表中多余的重復記錄(多個字段),不包含rowid最小的記錄

select * from table a
where (a.UserId,a.seq) in
(select UserId,seq from table group by UserId,seq having count(*) > 1)
and rowid not in
(select min(rowid) from table group by UserId,seq having count(*)>1)

二十三、 MySQL 時間類型 datetime、bigint 及 timestamp 的查詢效率

1??sql查詢速率:在InnoDB存儲引擎下,通過時間范圍查找,性能bigint > datetime > timestamp
2??sql分組速率:在InnoDB存儲引擎下,通過時間分組,性能timestamp > datetime,但是相差不大
3??sql排序速率:在InnoDB存儲引擎下,通過時間排序,性能bigint > timestamp > datetime

如果需要對時間字段進行操作(如通過時間范圍查找或者排序等),推薦使用bigint;如果時間字段不需要進行任何操作,推薦使用timestamp,使用4個字節保存比較節省空間,但是只能記錄到2038年記錄的時間有限。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370