MySQL慢查詢優(yōu)化(線上案例調(diào)優(yōu))

本文已收錄到1.1K Star數(shù)開源學(xué)習(xí)指南——《大廠面試指北》,如果想要了解更多大廠面試相關(guān)的內(nèi)容及獲取《大廠面試指北》離線PDF版羡亩,請掃描下方二維碼碼關(guān)注公眾號“大廠面試”丹禀,謝謝大家了状勤!

《大廠面試指北》最佳閱讀地址:

http://notfound9.github.io/interviewGuide/

《大廠面試指北》項(xiàng)目地址:

https://github.com/NotFound9/interviewGuide

獲取《大廠面試指北》離線PDF版,請掃描下方二維碼關(guān)注公眾號“大廠面試”

image.png

《大廠面試指北》項(xiàng)目截圖:

image.png

文章說明

這篇文章主要是記錄自己最近在真實(shí)工作中遇到的慢查詢的案例湃崩,然后進(jìn)行調(diào)優(yōu)分析的過程荧降,歡迎大家一起討論調(diào)優(yōu)經(jīng)驗(yàn)。(以下出現(xiàn)的表名攒读,列名都是化名朵诫,實(shí)際數(shù)據(jù)也進(jìn)行過一點(diǎn)微調(diào)。)

一.復(fù)雜的深分頁問題優(yōu)化

背景

有一個(gè)article表薄扁,用于存儲文章的基本信息的剪返,有文章id废累,作者id等一些屬性,有一個(gè)content表脱盲,主要用于存儲文章的內(nèi)容邑滨,主鍵是article_id,需求需要將一些滿足條件的作者發(fā)布的文章導(dǎo)入到另外一個(gè)庫钱反,所以我同事就在項(xiàng)目中先查詢出了符合條件的作者id掖看,然后開啟了多個(gè)線程,每個(gè)線程每次取一個(gè)作者id面哥,執(zhí)行查詢和導(dǎo)入工作哎壳。

查詢出作者id是1111,名下的所有文章信息尚卫,文章內(nèi)容相關(guān)的信息的SQL如下:

SELECT
    a.*, c.*
FROM
    article a
LEFT JOIN content c ON a.id = c.article_id
WHERE
    a.author_id = 1111
AND a.create_time < '2020-04-29 00:00:00'
LIMIT 210000,100

因?yàn)椴樵兊倪@個(gè)數(shù)據(jù)庫是機(jī)械硬盤的归榕,在offset查詢到20萬時(shí),查詢時(shí)間已經(jīng)特別長了吱涉,運(yùn)維同事那邊直接收到報(bào)警刹泄,說這個(gè)庫已經(jīng)IO阻塞了,已經(jīng)多次進(jìn)行主從切換了怎爵,我們就去navicat里面試著執(zhí)行了一下這個(gè)語句特石,也是一直在等待, 然后對數(shù)據(jù)庫執(zhí)行show proceesslist 命令查看了一下疙咸,發(fā)現(xiàn)每個(gè)查詢都是處于Writing to net的狀態(tài)县匠,沒辦法只能先把導(dǎo)入的項(xiàng)目暫時(shí)下線,然后執(zhí)行kill命令將當(dāng)前的查詢都?xì)⑺肋M(jìn)程(因?yàn)橹皇强蛻舳薙top的話撒轮,MySQL服務(wù)端會繼續(xù)查詢)。

然后我們開始分析這條命令執(zhí)行慢的原因:

是否是聯(lián)合索引的問題

當(dāng)前是索引情況如下:

article表的主鍵是id贼穆,author_id是一個(gè)普通索引
content表的主鍵是article_id

所以認(rèn)為當(dāng)前是執(zhí)行流程是先去article表的普通索引author_id里面找到1111的所有文章id题山,然后根據(jù)這些文章id去article表的聚集索引中找到所有的文章,然后拿每個(gè)文章id去content表中找文章內(nèi)容等信息故痊,然后判斷create_time是否滿足要求顶瞳,進(jìn)行過濾,最終找到offset為20000后的100條數(shù)據(jù)愕秫。

所以我們就將article的author_id索引改成了聯(lián)合索引(author_id,create_time),這樣聯(lián)合索引(author_id,create_time)中的B+樹就是先安裝author_id排序慨菱,再按照create_time排序,這樣一開始在聯(lián)合(author_id,create_time)查詢出來的文章id就是滿足create_time < '2020-04-29 00:00:00'條件的戴甩,后面就不用進(jìn)行過濾了符喝,就不會就是符合就不用對create_time過濾。

流程確實(shí)是這個(gè)流程甜孤,但是去查詢時(shí)协饲,如果limit還是210000, 100時(shí)畏腕,還是查不出數(shù)據(jù),幾分鐘都沒有數(shù)據(jù)茉稠,一直到navica提示超時(shí)描馅,使用Explain看的話,確實(shí)命中索引了而线,如果將offset調(diào)小铭污,調(diào)成6000, 100,勉強(qiáng)可以查出數(shù)據(jù)膀篮,但是需要46s况凉,所以瓶頸不在這里。

真實(shí)原因如下:

先看關(guān)于深分頁的兩個(gè)查詢各拷,id是主鍵刁绒,val是普通索引

直接查詢法

select * from test where val=4 limit 300000,5;

先查主鍵再join

select * from test a 
inner join
(select id from test where val=4 limit 300000,5) as b 
on a.id=b.id;

這兩個(gè)查詢的結(jié)果都是查詢出offset是30000后的5條數(shù)據(jù),區(qū)別在于第一個(gè)查詢需要先去普通索引val中查詢出300005個(gè)id烤黍,然后去聚集索引下讀取300005個(gè)數(shù)據(jù)頁知市,然后拋棄前面的300000個(gè)結(jié)果,只返回最后5個(gè)結(jié)果速蕊,過程中會產(chǎn)生了大量的隨機(jī)I/O嫂丙。第二個(gè)查詢一開始在普通索引val下就只會讀取后5個(gè)id,然后去聚集索引下讀取5個(gè)數(shù)據(jù)頁规哲。

同理我們業(yè)務(wù)中那條查詢其實(shí)是更加復(fù)雜的情況跟啤,因?yàn)槲覀儤I(yè)務(wù)的那條SQL不僅會讀取article表中的210100條結(jié)果,而且會每條結(jié)果去content表中查詢文章相關(guān)內(nèi)容唉锌,而這張表有幾個(gè)TEXT類型的字段隅肥,我們使用show table status命令查看表相關(guān)的信息發(fā)現(xiàn)

Name Engine Row_format Rows Avg_Row_length
article InnoDB Compact 2682682 266
content InnoDB Compact 2824768 16847

發(fā)現(xiàn)兩個(gè)表的數(shù)據(jù)量都是200多萬的量級,article表的行平均長度是266袄简,content表的平均長度是16847腥放,簡單來說是當(dāng) InnoDB 使用 Compact 或者 Redundant 格式存儲極長的 VARCHAR 或者 BLOB 這類大對象時(shí),我們并不會直接將所有的內(nèi)容都存放在數(shù)據(jù)頁節(jié)點(diǎn)中绿语,而是將行數(shù)據(jù)中的前 768 個(gè)字節(jié)存儲在數(shù)據(jù)頁中秃症,后面會通過偏移量指向溢出頁。

(詳細(xì)了解可以看看這篇文章深度好文帶你讀懂MySQL和InnoDB

img

這樣再從content表里面查詢連續(xù)的100行數(shù)據(jù)時(shí)吕粹,讀取每行數(shù)據(jù)時(shí)种柑,還需要去讀溢出頁的數(shù)據(jù),這樣就需要大量隨機(jī)IO匹耕,因?yàn)闄C(jī)械硬盤的硬件特性聚请,隨機(jī)IO會比順序IO慢很多。所以我們后來又進(jìn)行了測試泌神,

只是從article表里面查詢limit 200000良漱,100的數(shù)據(jù)舞虱,發(fā)現(xiàn)即便存在深分頁的問題,查詢時(shí)間只是0.5s母市,因?yàn)閍rticle表的平均列長度是266矾兜,所有數(shù)據(jù)都存在數(shù)據(jù)頁節(jié)點(diǎn)中,不存在頁溢出患久,所以都是順序IO椅寺,所以比較快。

//查詢時(shí)間0.51s
SELECT a.* FROM article a  
WHERE a.author_id = 1111  
AND a.create_time < '2020-04-29 00:00:00' 
LIMIT 200100, 100

相反的蒋失,我們直接先找出100個(gè)article_id去content表里面查詢數(shù)據(jù)返帕,發(fā)現(xiàn)比較慢,第一次查詢時(shí)需要3s左右(也就是這些id的文章內(nèi)容相關(guān)的信息都沒有過篙挽,沒有緩存的情況)荆萤,第二次查詢時(shí)因?yàn)檫@些溢出頁數(shù)據(jù)已經(jīng)加載到buffer pool,所以大概0.04s铣卡。

SELECT SQL_NO_CACHE c.* 
FROM article_content c 
WHERE c.article_id in(100個(gè)article_id)

解決方案

所以針對這個(gè)問題的解決方案主要有兩種:

先查出主鍵id再inner join

非連續(xù)查詢的情況下链韭,也就是我們在查第100頁的數(shù)據(jù)時(shí),不一定查了第99頁煮落,也就是允許跳頁查詢的情況敞峭,那么就是使用先查主鍵再join這種方法對我們的業(yè)務(wù)SQL進(jìn)行改寫成下面這樣,下查詢出210000, 100時(shí)主鍵id蝉仇,作為臨時(shí)表temp_table旋讹,將article表與temp_table表進(jìn)行inner join,查詢出中文章相關(guān)的信息轿衔,并且去left Join content表查詢文章內(nèi)容相關(guān)的信息沉迹。 第一次查詢大概1.11s,后面每次查詢大概0.15s

SELECT
    a.*, c.*
FROM article a
INNER JOIN(
    SELECT  id FROM article a
    WHERE   a.author_id = 1111
    AND a.create_time < '2020-04-29 00:00:00'
    LIMIT 210000 ,
    100
) as temp_table ON a.id = temp_table.id
LEFT JOIN content c ON a.id = c.article_id

優(yōu)化結(jié)果

優(yōu)化前呀枢,offset達(dá)到20萬的量級時(shí)胚股,查詢時(shí)間過長,一直到超時(shí)裙秋。

優(yōu)化后,offset達(dá)到20萬的量級時(shí)缨伊,查詢時(shí)間為1.11s摘刑。

利用范圍查詢條件來限制取出的數(shù)據(jù)

這種方法的大致思路如下,假設(shè)要查詢test_table中offset為10000的后100條數(shù)據(jù)刻坊,假設(shè)我們事先已知第10000條數(shù)據(jù)的id枷恕,值為min_id_value

select * from test_table where id > min_id_value order by id limit 0, 100,就是即利用條件id > min_id_value在掃描索引是跳過10000條記錄谭胚,然后取100條數(shù)據(jù)即可徐块,這種處理方式的offset值便成為0了未玻,但此種方式有限制,必須知道offset對應(yīng)id胡控,然后作為min_id_value扳剿,增加id > min_id_value的條件來進(jìn)行過濾,如果是用于分頁查找的話昼激,也就是必須知道上一頁的最大的id庇绽,所以只能一頁一頁得查,不能跳頁橙困,但是因?yàn)槲覀兊臉I(yè)務(wù)需求就是每次100條數(shù)據(jù)瞧掺,進(jìn)行分批導(dǎo)數(shù)據(jù),所以我們這種場景是可以使用凡傅。針對這種方法辟狈,我們的業(yè)務(wù)SQL改寫如下:

//先查出最大和最小的id
SELECT min(a.id) as min_id , max(a.id) as max_id 
FROM article a 
WHERE a.author_id = 1111  
AND a.create_time < '2020-04-29 00:00:00' 
//然后每次循環(huán)查找
while(min_id<max_id) {
        SELECT a.*, c.* FROM article a LEFT JOIN content c ON a.id = c.article_id  WHERE a.author_id = 1111  AND a.id > min_id LIMIT 100
        //這100條數(shù)據(jù)導(dǎo)入完畢后,將100條數(shù)據(jù)數(shù)據(jù)中最大的id賦值給min_id夏跷,以便導(dǎo)入下100條數(shù)據(jù)
}

優(yōu)化結(jié)果

優(yōu)化前哼转,offset達(dá)到20萬的量級時(shí),查詢時(shí)間過長拓春,一直到超時(shí)释簿。

優(yōu)化后,offset達(dá)到20萬的量級時(shí)硼莽,由于知道第20萬條數(shù)據(jù)的id庶溶,查詢時(shí)間為0.34s。

二.聯(lián)合索引問題優(yōu)化

聯(lián)合索引其實(shí)有兩個(gè)作用:

1.充分利用where條件懂鸵,縮小范圍

例如我們需要查詢以下語句:

SELECT * FROM test WHERE a = 1 AND b = 2

如果對字段a建立單列索引偏螺,對b建立單列索引,那么在查詢時(shí)匆光,只能選擇走索引a套像,查詢所有a=1的主鍵id,然后進(jìn)行回表终息,在回表的過程中夺巩,在聚集索引中讀取每一行數(shù)據(jù),然后過濾出b = 2結(jié)果集周崭,或者走索引b柳譬,也是這樣的過程。
如果對a续镇,b建立了聯(lián)合索引(a,b),那么在查詢時(shí)美澳,直接在聯(lián)合索引中先查到a=1的節(jié)點(diǎn),然后根據(jù)b=2繼續(xù)往下查,查出符合條件的結(jié)果集制跟,進(jìn)行回表舅桩。

2.避免回表(此時(shí)也叫覆蓋索引)

這種情況就是假如我們只查詢某幾個(gè)常用字段,例如查詢a和b如下:

SELECT a,b FROM test WHERE a = 1 AND b = 2

對字段a建立單列索引雨膨,對b建立單列索引就需要像上面所說的擂涛,查到符合條件的主鍵id集合后需要去聚集索引下回表查詢,但是如果我們要查詢的字段本身在聯(lián)合索引中就都包含了哥放,那么就不用回表了歼指。

3.減少需要回表的數(shù)據(jù)的行數(shù)

這種情況就是假如我們需要查詢a>1并且b=2的數(shù)據(jù)

SELECT * FROM test WHERE a > 1 AND b = 2

如果建立的是單列索引a,那么在查詢時(shí)會在單列索引a中把a(bǔ)>1的主鍵id全部查找出來然后進(jìn)行回表甥雕。
如果建立的是聯(lián)合索引(a,b),基于最左前綴匹配原則踩身,因?yàn)閍的查詢條件是一個(gè)范圍查找(=或者in之外的查詢條件都是范圍查找),這樣雖然在聯(lián)合索引中查詢時(shí)只能命中索引a的部分社露,b的部分命中不了挟阻,只能根據(jù)a>1進(jìn)行查詢,但是由于聯(lián)合索引中每個(gè)葉子節(jié)點(diǎn)包含b的信息峭弟,在查詢出所有a>1的主鍵id時(shí)附鸽,也會對b=2進(jìn)行篩選,這樣需要回表的主鍵id就只有a>1并且b=2這部分了瞒瘸,所以回表的數(shù)據(jù)量會變小坷备。

我們業(yè)務(wù)中碰到的就是第3種情況,我們的業(yè)務(wù)SQL本來更加復(fù)雜情臭,還會join其他表省撑,但是由于優(yōu)化的瓶頸在于建立聯(lián)合索引,所以進(jìn)行了一些簡化俯在,下面是簡化后的SQL:

SELECT
  a.id as article_id ,
  a.title as title ,
  a.author_id as author_id 
from
  article a
where
  a.create_time between '2020-03-29 03:00:00.003'
and '2020-04-29 03:00:00.003'
and a.status = 1

我們的需求其實(shí)就是從article表中查詢出最近一個(gè)月竟秫,status為1的文章,我們本來就是針對create_time建了單列索引跷乐,結(jié)果在慢查詢?nèi)罩局邪l(fā)現(xiàn)了這條語句肥败,查詢時(shí)間需要0.91s左右,所以開始嘗試著進(jìn)行優(yōu)化愕提。

為了便于測試馒稍,我們在表中分別對create_time建立了單列索引create_time,對(create_time,status)建立聯(lián)合索引idx_createTime_status浅侨。

強(qiáng)制使用idx_createTime進(jìn)行查詢

SELECT
  a.id as article_id ,
  a.title as title ,
  a.author_id as author_id 
from
  article a  FORCE INDEX(idx_createTime)
where
  a.create_time between '2020-03-22 03:00:00.003'
and '2020-04-22 03:00:00.003'
and a.status = 1

強(qiáng)制使用idx_createTime_status進(jìn)行查詢(即使不強(qiáng)制也是會選擇這個(gè)索引)

SELECT
  a.id as article_id ,
  a.title as title ,
  a.author_id as author_id 
from
  article a  FORCE INDEX(idx_createTime_status)
where
  a.create_time between '2020-03-22 03:00:00.003'
and '2020-04-22 03:00:00.003'
and a.status = 1

優(yōu)化結(jié)果:

優(yōu)化前使用idx_createTime單列索引筷黔,查詢時(shí)間為0.91s

優(yōu)化前使用idx_createTime_status聯(lián)合索引,查詢時(shí)間為0.21s

EXPLAIN的結(jié)果如下:

id type key key_len rows filtered Extra
1 range idx_createTime 4 311608 25.00 Using index condition; Using where
2 range idx_createTime_status 6 310812 100.00 Using index condition

原理分析

先介紹一下EXPLAIN中Extra列的各種取值的含義

Using filesort

當(dāng)Query 中包含 ORDER BY 操作仗颈,而且無法利用索引完成排序操作的時(shí)候,MySQL Query Optimizer 不得不選擇相應(yīng)的排序算法來實(shí)現(xiàn)。數(shù)據(jù)較少時(shí)從內(nèi)存排序挨决,否則從磁盤排序请祖。Explain不會顯示的告訴客戶端用哪種排序。

Using index

僅使用索引樹中的信息從表中檢索列信息脖祈,而不需要進(jìn)行附加搜索來讀取實(shí)際行(使用二級覆蓋索引即可獲取數(shù)據(jù))肆捕。 當(dāng)查詢僅使用作為單個(gè)索引的一部分的列時(shí),可以使用此策略盖高。

Using temporary

要解決查詢慎陵,MySQL需要創(chuàng)建一個(gè)臨時(shí)表來保存結(jié)果。 如果查詢包含不同列的GROUP BY和ORDER BY子句喻奥,則通常會發(fā)生這種情況席纽。官方解釋:”為了解決查詢,MySQL需要創(chuàng)建一個(gè)臨時(shí)表來容納結(jié)果撞蚕。典型情況如查詢包含可以按不同情況列出列的GROUP BY和ORDER BY子句時(shí)润梯。很明顯就是通過where條件一次性檢索出來的結(jié)果集太大了,內(nèi)存放不下了纺铭,只能通過加臨時(shí)表來輔助處理。

Using where

表示當(dāng)where過濾條件中的字段無索引時(shí)刀疙,MySQL Sever層接收到存儲引擎(例如innodb)的結(jié)果集后谦秧,根據(jù)where條件中的條件進(jìn)行過濾竟纳。

Using index condition

Using index condition 會先條件過濾索引,過濾完索引后找到所有符合索引條件的數(shù)據(jù)行油够,隨后用 WHERE 子句中的其他條件去過濾這些數(shù)據(jù)行蚁袭;

我們的實(shí)際案例中,其實(shí)就是走單個(gè)索引idx_createTime時(shí)石咬,只能從索引中查出 滿足a.create_time between '2020-03-22 03:00:00.003' and '2020-04-22 03:00:00.003'條件的主鍵id揩悄,然后進(jìn)行回表,因?yàn)閕dx_createTime索引中沒有status的信息鬼悠,只能回表后查出所有的主鍵id對應(yīng)的行删性。然后innodb將結(jié)果集返回給MySQL Sever,MySQL Sever根據(jù)status字段進(jìn)行過濾焕窝,篩選出status為1的字段蹬挺,所以第一個(gè)查詢的Explain結(jié)果中的Extra才會顯示Using where。

filtered字段表示存儲引擎返回的數(shù)據(jù)在server層過濾后它掂,剩下多少滿足查詢的記錄數(shù)量的比例巴帮,這個(gè)是預(yù)估值溯泣,因?yàn)閟tatus取值是null,1榕茧,2垃沦,3,4用押,所以這里給的25%肢簿。

所以第二個(gè)查詢與第一個(gè)查詢的區(qū)別主要在于一開始去idx_createTime_status查到的結(jié)果集就是滿足status是1的id,所以去聚集索引下進(jìn)行回表查詢時(shí)蜻拨,掃描的行數(shù)會少很多(大概是2.7萬行與15萬行的區(qū)別)池充,之后innodb返回給MySQL Server的數(shù)據(jù)就是滿足條件status是1的結(jié)果集(2.7萬行),不用再進(jìn)行篩選了缎讼,所以第二個(gè)查詢才會快這么多收夸,時(shí)間是優(yōu)化前的23%。(兩種查詢方式的EXPLAIN預(yù)估掃描行數(shù)都是30萬行左右是因?yàn)閕dx_createTime_status只命中了createTime休涤,因?yàn)閏reateTime不是查單個(gè)值咱圆,查的是范圍)

//查詢結(jié)果行數(shù)是15萬行左右
SELECT count(*) from article a 
where a.post_time 
between '2020-03-22 03:00:00.003' and '2020-04-22 03:00:00.003'

//查詢結(jié)果行數(shù)是2萬6行左右
SELECT count(*) from article a 
where a.post_time 
between '2020-03-22 03:00:00.003' and '2020-04-22 03:00:00.003' 
and a.audit_status = 1

發(fā)散思考:如果將聯(lián)合索引(createTime,status)改成(status功氨,createTime)會怎么樣序苏?

where
  a.create_time between '2020-03-22 03:00:00.003'
and '2020-04-22 03:00:00.003'
and a.status = 1

根據(jù)最左匹配的原則,因?yàn)槲覀兊膚here查詢條件是這樣捷凄,如果是(createTime忱详,status)那么索引就只能用到createTime,如果是(status跺涤,createTime)匈睁,因?yàn)閟tatus是查詢單個(gè)值,所以status桶错,createTime都可以命中航唆,在(status,createTime)索引中掃描行數(shù)會減少院刁,但是由于(createTime糯钙,status)這個(gè)索引本身值包含createTime,status退腥,id三個(gè)字段的信息任岸,數(shù)據(jù)量比較小,而一個(gè)數(shù)據(jù)頁是16k狡刘,可以存儲1000個(gè)以上的索引數(shù)據(jù)節(jié)點(diǎn)享潜,而且是查詢到createTime后,進(jìn)行的順序IO嗅蔬,所以讀取比較快剑按,總得的查詢時(shí)間兩者基本是一致疾就。下面是測試結(jié)果:

首先創(chuàng)建了(status,createTime)名叫idx_status_createTime吕座,

SELECT
  a.id as article_id ,
  a.title as title ,
  a.author_id as author_id 
from
  article a  FORCE INDEX(idx_status_createTime)
where
  a.create_time between '2020-03-22 03:00:00.003'
and '2020-04-22 03:00:00.003'
and a.status = 1

查詢時(shí)間是0.21虐译,跟第二種方式(createTime,status)索引的查詢時(shí)間基本一致吴趴。

Explain結(jié)果對比:

id type key key_len rows filtered Extra
2 range idx_createTime_status 6 310812 100.00 Using index condition
3 range idx_status_createTime 6 52542 100.00 Using index condition

掃描行數(shù)確實(shí)會少一些,因?yàn)樵趇dx_status_createTime的索引中侮攀,一開始根據(jù)status = 1排除掉了status取值為其他值的情況锣枝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市兰英,隨后出現(xiàn)的幾起案子撇叁,更是在濱河造成了極大的恐慌,老刑警劉巖畦贸,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陨闹,死亡現(xiàn)場離奇詭異,居然都是意外死亡薄坏,警方通過查閱死者的電腦和手機(jī)趋厉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胶坠,“玉大人君账,你說我怎么就攤上這事∩蛏疲” “怎么了乡数?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長闻牡。 經(jīng)常有香客問我净赴,道長,這世上最難降的妖魔是什么罩润? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任玖翅,我火速辦了婚禮,結(jié)果婚禮上哨啃,老公的妹妹穿的比我還像新娘烧栋。我一直安慰自己,他們只是感情好拳球,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布审姓。 她就那樣靜靜地躺著,像睡著了一般祝峻。 火紅的嫁衣襯著肌膚如雪魔吐。 梳的紋絲不亂的頭發(fā)上扎筒,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機(jī)與錄音酬姆,去河邊找鬼嗜桌。 笑死,一個(gè)胖子當(dāng)著我的面吹牛辞色,可吹牛的內(nèi)容都是我干的骨宠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼相满,長吁一口氣:“原來是場噩夢啊……” “哼层亿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起立美,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤匿又,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后建蹄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碌更,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年洞慎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了痛单。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拢蛋,死狀恐怖桦他,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谆棱,我是刑警寧澤快压,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站垃瞧,受9級特大地震影響蔫劣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜个从,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一脉幢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嗦锐,春花似錦嫌松、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至碳默,卻和暖如春贾陷,著一層夾襖步出監(jiān)牢的瞬間缘眶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工髓废, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巷懈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓慌洪,卻偏偏與公主長得像顶燕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子蒋譬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354