55-MySQL索引优化与查询优化-单表

一、数据库调优

1.1、调优维度

  • 1、索引失效、没有充分利用到索引——索引建立
  • 2、关联查询太多JOIN(设计缺陷或不得已的需求)——SQL优化
  • 3、服务器调优及各个参数设置(缓存、线程数等)——调整 my.cnf
  • 4、数据过多——分库分表

1.2、物理查询优化

物理查询优化是通过索引表连接方式等技术来进行优化

1.3、逻辑查询优化

逻辑查询优化是通过 SQL 等价变换 提升查询效率,直白一点就是说,换一种查询写法执行效率可能更高

二、数据准备

2.1、建表

  • class 表
CREATE TABLE `class`
(
    `id`        INT(11) NOT NULL AUTO_INCREMENT,
    `classname` VARCHAR(30) DEFAULT NULL,
    `address`   VARCHAR(40) DEFAULT NULL,
    `monitor`   INT     NULL,
    PRIMARY KEY (`id`)
);
  • student 表
CREATE TABLE `student`
(
    `id`      INT(11) NOT NULL AUTO_INCREMENT,
    `stuno`   INT     NOT NULL,
    `name`    VARCHAR(20) DEFAULT NULL,
    `age`     INT(3)      DEFAULT NULL,
    `classid` INT(11)     DEFAULT NULL,
    PRIMARY KEY (`id`)
    #CONSTRAINT `fk_class_id` FOREIGN KEY (`classId`) REFERENCES `t_class` (`id`)
);

2.2、设置参数

  • 命令开启:允许创建函数设置
# 不加global只是当前窗口有效
SET GLOBAL log_bin_trust_function_creators = 1;

2.3、创建函数

  • 随机产生字符串
DELIMITER $
CREATE FUNCTION rand_string(n INT) RETURNS VARCHAR(255)
BEGIN
    DECLARE chars_str VARCHAR(100) DEFAULT 'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
    DECLARE return_str VARCHAR(255) DEFAULT '';
    DECLARE i INT DEFAULT 0;
    WHILE i < n
        DO
            SET return_str = CONCAT(return_str, SUBSTRING(chars_str, FLOOR(1 + RAND() * 52), 1));
            SET i = i + 1;
        END WHILE;
    RETURN return_str;
END $
DELIMITER ;
  • 用于随机产生多少到多少的编号
DELIMITER $
CREATE FUNCTION rand_num(from_num INT, to_num INT) RETURNS INT(11)
BEGIN
    DECLARE i INT DEFAULT 0;
    SET i = FLOOR(from_num + RAND() * (to_num - from_num + 1));
    RETURN i;
END $
DELIMITER ;
  • 创建往stu表中插入数据的存储过程
DELIMITER $
CREATE PROCEDURE insert_stu(start INT, max_num INT)
BEGIN
    DECLARE i INT DEFAULT 0;
    SET autocommit = 0; #  设置手动提交事务
    REPEAT
        #循环
        SET i = i + 1; #  赋值
        INSERT INTO student (stuno, name, age, classid)
        VALUES ((start + i), rand_string(6), rand_num(1, 50), rand_num(1, 1000));
    UNTIL i = max_num
        END REPEAT;
    COMMIT; #  提交事务
END $
DELIMITER ;
  • 执行存储过程,往class表添加随机数据
DELIMITER $
CREATE PROCEDURE `insert_class`(max_num INT)
BEGIN
    DECLARE i INT DEFAULT 0;
    SET autocommit = 0;
    REPEAT
        SET i = i + 1;
        INSERT INTO class (classname, address, monitor) VALUES (rand_string(8), rand_string(10), rand_num(1, 100000));
    UNTIL i = max_num
        END REPEAT;
    COMMIT;
END $
DELIMITER ;
  • 调用存储过程
#  执行存储过程,往class表添加1万条数据
CALL insert_class(10000);

#  执行存储过程,往stu表添加50万条数据
CALL insert_stu(100000, 500000);
  • 销毁索引
DELIMITER $
CREATE PROCEDURE `proc_drop_index`(dbname VARCHAR(200), tablename VARCHAR(200))
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE ct INT DEFAULT 0;
    DECLARE _index VARCHAR(200) DEFAULT '';
    DECLARE _cur CURSOR FOR SELECT index_name
                            FROM information_schema.statistics
                            WHERE table_schema = dbname
                              AND table_name = tablename
                              AND seq_in_index = 1
                              AND index_name <> 'PRIMARY';
#   每个游标必须使用不同的declare continue handler for not found set done=1来控制游标的结束
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 2;
#   若没有数据返回,程序继续,并将变量done设为2
    OPEN _cur;
    FETCH _cur INTO _index;
    WHILE _index <> ''
        DO
            SET @str = CONCAT("drop index ", _index, " on ", tablename);
            PREPARE sql_str FROM @str;
            EXECUTE sql_str;
            DEALLOCATE PREPARE sql_str;
            SET _index = '';
            FETCH _cur INTO _index;
        END WHILE;
    CLOSE _cur;
END $
DELIMITER ;
  • 调用存储过程
CALL proc_drop_index("dbname","tablename");

三、索引失效

  • MySQL中 提高性能 的一个最有效的方式是对数据表 设计合理的索引。索引提供了高效访问数据的方法,并且加快查询的速度,因此索引对查询的速度有着至关重要的影响。

    • 使用索引可以快速地定位表中的某条记录,从而提高数据库查询的速度,提高数据库的性能
    • 如果查询时没有使用索引,查询语句就会扫描表中的所有记录。在数据量大的情况下,这样查询的速度回很慢
  • 大多数情况下采用B+树来构建索引。只是空间列类型的索引使用R-树,并且MEMORY表还支持hash索引

  • 其实,用不用所以,最终都是优化器说了算。优化器是基于什么的优化器?基因cost开销(CostBaseOptimizer),它不是基于规则(Rule-BasedOptimizer),也不是基于语义,怎么样开销小就怎么样来。

  • SQL语句是否使用索引,跟数据库版本数据量数据选择度都有关系

3.1、案例1——全值匹配我最爱

3.1.1、查看student表索引情况

  • 查看命令
SHOW INDEX FROM student;
student表索引.png

3.1.2、通过 age 来查询

  • SQL
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age=30;
  • EXPLAIN结果
    EXPLAIN结果.png

3.1.2、通过 ageclassId来查询

  • SQL
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age=30 AND classId=4;
  • EXPLAIN结果
    EXPLAIN结果.png

3.1.3、通过 ageclassIdNAME来查询

  • SQL
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age=30 AND classId=4 AND NAME = 'abcd';
  • EXPLAIN结果
    EXPLAIN结果.png

3.1.3、小结

由于student表没有索引,所以上述查询都是全表扫描

3.1.4、给age添加索引

  • SQL
CREATE INDEX idx_age ON student (age);
  • 查询
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age = 30;

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age = 30
  AND classid = 4;

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age = 30
  AND classid = 4
  AND name = 'abcd';
  • EXPLAIN结果
    EXPLAIN结果.png
  • 查询使用了索引idx_age

3.1.5、使用ageclassid创建联合索引

  • 创建联合索引
CREATE INDEX idx_age_classid ON student(age,classId);

3.1.5.1 通过 age 查询

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age = 30;
  • EXPLAIN结果
    EXPLAIN结果.png
  • 小结
    • 可选 idx_age,idx_age_classid 两个索引
    • 最终选用了idx_age
    • key_len=5:age为INT类型占用 4字节+可以为NULL

3.1.5.2 通过 ageclassid 查询

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age = 30
  AND classid = 4;
  • EXPLAIN分析
    EXPLAIN分析.png
  • 小结
    • 可选 idx_age,idx_age_classid 两个索引
    • 最终选用了idx_age_classid
    • key_len=10:age为INT类型占用 4字节+可以为NULL;同理classid为INT类型占用 4字节+可以为NULL

3.1.5.3 通过 ageclassidname 查询

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age = 30
  AND classid = 4
  AND name = 'abcd';
  • EXPLAIN分析
    EXPLAIN分析.png
  • 小结:使用索引情况与上面一致

3.1.6、使用ageclassidname创建联合索引

  • 创建联合索引
CREATE INDEX idx_age_classid_name ON student (age, classid, name);

3.1.6.1 通过 age 查询

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age = 30;
  • EXPLAIN分析
    EXPLAIN分析.png
  • 小结
    • 可选 idx_age,idx_age_classid,idx_age_classid_name 3个索引
    • 最终选用了idx_age
    • key_len=5:age为INT类型占用 4字节+可以为NULL

3.1.6.2 通过 ageclassid 查询

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age = 30
  AND classid = 4;
  • EXPLAIN分析
    EXPLAIN分析.png
  • 小结

    • 可选 idx_age,idx_age_classid,idx_age_classid_name 3个索引
    • 最终选用了idx_age_classid
    • key_len=10:age为INT类型占用 4字节+可以为NULL;同理classid为INT类型占用 4字节+可以为NULL

3.1.6.3 通过 ageclassidname 查询

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age = 30
  AND classid = 4
  AND name = 'abcd';
  • EXPLAIN分析
    EXPLAIN分析.png
  • 小结

    • 可选 idx_age,idx_age_classid,idx_age_classid_name 3个索引
    • 最终选用了idx_age_classid_name
    • key_len=93:age为INT类型占用 4字节+可以为NULL(1字节);同理classid为INT类型占用 4字节+可以为NULL(1字节) + name为varchar(20)类型占用80字节+可以为NULL(1字节)+可变字符(2字节)

3.1.7、查看索引

SHOW INDEX FROM student;
  • student表索引
    student表索引.png

3.1.8、查看冗余索引

SELECT *
FROM sys.schema_redundant_indexes;
冗余索引.png

解决冗余索引.png

3.1.9、删除冗余索引

ALTER TABLE `atguigudb2`.`student` DROP INDEX `idx_age`;

ALTER TABLE `atguigudb2`.`student` DROP INDEX `idx_age_classid`;

3.1.10、再次查看索引

SHOW INDEX FROM student;
image.png

3.1.11、再次查看上述

  • 使用age来查询
    使用`age`来查询.png
  • 使用ageclassid来查询
    使用`age`和`classid`来查询.png
  • 使用ageclassidname来查询
    使用`age`和`classid`和`name`来查询.png

3.1.12、小结

  • 删除索引idx_ageidx_age_classid后,上述查询并不受影响
  • 所以直接使用idx_age_classid_name就可以满足上述查询

3.2、案例2——最佳左前缀法则

在MySQL建立联合索引时会遵守最佳左前缀匹配原则,即最左优先,在检索数据时从联合索引的最左边开始匹配

3.2.1、使用agename来查询

  • SQL
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age = 30
  AND name = 'abcd';
  • EXPLAIN结果
    image.png
  • 分析:使用到部分索引

    • 1、可选 idx_age_classid_name 索引
    • 2、最终选用 idx_age_classid_name 索引
    • 3、key_len=5:age为INT类型占用 4字节+可以为NULL占用 1 字节;
    • 4、name字段没有使用到索引

3.2.2、使用classidname来查询

  • SQL
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE classid = 4
  AND name = 'abcd';
  • EXPLAIN结果
    image.png
  • 分析:完全没有使用到索引

3.2.3、小结

MySQL可以为多个字段创建索引,一个索引可以包含 16个字段。对于多列索引,过滤条件要使用索引必须按照索引建立时的顺序,依次满足,一旦跳过某个字段,索引后面的字段都无法被使用。如果查询条件中没有使用这些字段中第 1 个字段时,多列(联合)索引不会被使用

3.3、主键插入顺序

对于一个使用InnoDB存储引擎的表来说,在我们没有显示的创建索引时,表中的数据实际上都是存储在聚簇索引的叶子节点的。而记录又是存储在数据页中的,数据页和记录又是按照记录主键值从小到大的顺序进行 排序,所以如果我们插入的记录的主键值是依次增大的话,那每插满一个数据页就换到下一个数据页继续插,而如果我们插入的主键值忽大忽小的话,就比较麻烦了,假设某个数据页存储的记录已经满了,它存储的主键值在1~100之间

3.3.1、主键插入顺序

一个完整数据页.png

3.3.2、插入一条主键值为9的记录
要在完整数据页中插入一条数据.png

  • 在数据页已经满的情况下,再插入数据改怎么办?

我们需要把当前 页面分裂 成两个页面,把本页中的一些记录移动到新创建的这个页中。页面分裂和记录移位意味着什么?意味着: 性能损耗 ! 所以如果我们想尽量避免这样无谓的性能损耗,最好让插入的记录的 主键值依次递增 ,这样就不会发生这样的性能损耗了。所以我们建议:让主键具有AUTO_INCREMENT ,让存储引擎自己为表生成主键,而不是我们手动插入

3.4、计算、函数、类型转换(自动或手动)导致索引失效

3.4.1、查看student表中索引,删除多余索引

  • 查看当前索引
SHOW INDEX FROM student;
image.png
  • 删除索引
DROP INDEX idx_age_classid_name ON student;
image.png

3.4.2、使用name查询

  • SQL
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE name LIKE 'abc%';
  • EXPLAIN
    没有使用索引.png
  • name字段创建索引

CREATE INDEX idx_name ON student(name);
当前索引.png
  • 再次使用name查询
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE name LIKE 'abc%';
  • EXPLAIN
    使用 idx_name 索引.png

3.4.3、使用name查询,由于使用函数造成索引失效

  • SQL
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE LEFT(name, 3) = 'abc';
  • EXPLAIN
    没有使用索引.png

3.4.4、使用计算造成索引失效

  • stuno字段创建索引
CREATE INDEX idx_sno ON student(stuno);
  • SQL
EXPLAIN SELECT SQL_NO_CACHE id, stuno, NAME FROM student WHERE stuno+1 = 900001;
索引失效.png
  • 索引可用
EXPLAIN SELECT SQL_NO_CACHE id, stuno, NAME FROM student WHERE stuno = 900001 - 1;
idx_sno索引可用.png

3.4.5、使用函数造成索引失效

  • stuno字段创建索引
CREATE INDEX idx_sno ON student(stuno);
  • SQL
EXPLAIN
SELECT id, stuno, name
FROM student
WHERE SUBSTRING(name, 1, 3) = 'abc';
索引失效.png
  • 索引优化
EXPLAIN
SELECT id, stuno, name
FROM student
WHERE name LIKE 'abc%';
  • EXPLAIN
    image.png

3.4.6、返回字段影响是否使用索引

  • 创建namestuno的联合索引idx_name_stuno
CREATE INDEX idx_name_stuno ON student (name, stuno);
  • 查询SQL
EXPLAIN
SELECT id, stuno, name
FROM student
WHERE SUBSTRING(name, 1, 3) = 'abc';
  • EXPLAIN
    image.png
  • 分析

虽然使用联合索引idx_name_stuno使查询使用了索引但是效果并不好,rows=499086ALL扫描数量一样多

3.4.7、类型转换导致索引失效

  • 当前索引
SHOW INDEX FROM student;
name索引.png
  • 使用name搜索
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE name=123;
  • EXPLAIN
    类型转换导致索引失效.png
  • 索引优化:name查询条件name='123'

EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE name='123';
  • EXPLAIN
    使用索引.png

3.4.8、范围条件右边的列索引失效

  • 清理索引
CALL proc_drop_index('atguigudb2','student');
  • 创建联合索引idx_age_classid_name(age, classid, name)
CREATE INDEX idx_age_classid_name ON student (age, classid, name);
  • 查询SQL
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE student.age = 30
  AND student.classid > 20
  AND student.name = 'abc';

或

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE student.age = 30
  AND student.name = 'abc'
  AND student.classid > 20;
  • EXPLAIN
    image.png
  • 分析:使用部分索引

    • 1、使用了idx_age_classid_name部分索引
    • 2、WHERE查询条件的先后顺序并不影响索引的是使用情况
    • 3、由于idx_age_classid_name索引在WHERE中由于classid使用了>(还有如:<、<=、>、>=、Between)造成索引断裂(索引失效)

优化索引

  • 创建新索引
CREATE INDEX idx_age_name_classid ON student (age, name, classid);
  • 再次查询
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE student.age = 30
  AND student.classid > 20
  AND student.name = 'abc';
  • EXPLAIN
    image.png

3.4.9、不等于(!= 或者<>)索引失效

  • 查询SQL
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE name <> 'abc';

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE name != 'abc';
  • EXPLAIN
    索引失效.png
  • 使用=

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE name = 'abc';
  • EXPLAIN
    使用索引.png

3.4.10、 IS NULL可以使用索引,IS NOT NULL无法使用索引

  • 创建索引
CREATE INDEX idx_name ON student(age);
  • 3.4.10.1、IS NULL 情况
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age IS NULL;
  • EXPLAIN
    IS NULL可以使用索引.png
  • 3.4.10.2、IS NOT NULL 情况

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE age IS NOT NULL;
  • EXPLAIN
    IS NOT NULL 无法使用索引.png
  • 小结

最好在设计数据表的时候将字段设置为 NOT NULL 约束,比如可以将 INT 类型的字段默认值设置为0;将字符类型的默认值设置为空字符串('')

  • 同理,在查询中使用NOT LIKE也无法使用索引,导致全表扫描

3.4.11、LIKE 以通配符%开头索引失效

在使用LIKE关键字进行查询的查询语句中,如果匹配字符串的第一个字符为%,索引将不会起作用;只要%不在第一个位置,索引才会起作用

  • 创建索引
CREATE INDEX idx_name ON student (name);
  • 3.4.11.1、以%开头匹配索引失效
EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE name LIKE '%ab%';
  • EXPLAIN
    以`%`开头匹配索引失效.png
  • 3.4.11.2、不以%开头可以使用索引

EXPLAIN
SELECT SQL_NO_CACHE *
FROM student
WHERE name LIKE 'ab%';
  • EXPLAIN
    image.png
  • 小结:页面搜索禁止左模糊或者全模糊,如果需要请走搜索引擎来解决

3.4.12、 OR 前后存在非索引的列,索引失效

WHERE 子句中,如果在 OR 前的条件列进行了索引,而在 OR 后的条件列没有进行索引,那么索引会失效。也就是说,OR 前后的两个条件中的列都是索引时,查询中才使用索引。因为 OR 的含义就是两个只要满足一个即可,因此只有一个条件列进行了索引是没有意义的,只要有条件列没有进行索引,就会进行 全表扫描 ,因此索引的条件也会失效。

  • age创建索引
CREATE INDEX idx_age ON student (age);
  • 查询SQL
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age = 10 OR classid = 100;
  • EXPLAIN
    因为 classid 字段上没有索引,索引查询语句没有使用索引.png
  • classid添加索引

CREATE INDEX idx_cid ON student (classid);
  • 查询SQL
EXPLAIN SELECT SQL_NO_CACHE * FROM student WHERE age = 10 OR classid = 100;
  • EXPLAIN
    index_merge.png
  • 小结:index_merge

因为age字段name字段上都有索引,所以查询中使用了索引。可以看到这里使用到了index_merge,简单来说 index_merge 就是对age字段name字段分别进行了扫描,然后将这两个结果集进行了合并。这样做的好处是避免了全表扫描

3.4.13、数据库和表的字符集统一使用utf8mb4

统一使用utf8mb4( 5.5.3版本以上支持)兼容性更好,统一字符集可以避免由于字符集转换产生的乱码。不同的 字符集 进行比较前需要进行 转换 会造成索引失效

3.4.14、小结

  • 对于单列索引,尽量选择针对当前 query 过滤性更好的索引

  • 在选择组合索引的时候,当前 query 中过滤性最好的字段在索引字段顺序中,位置越靠前越好

  • 在选择组合索引的时候,尽量选择能够包含当前 query 中的WHERE子句中更多字段的索引

  • 在选择组合索引的时候,如果某个字段可能出现范围查询时,尽量把这个字段放在索引次选的最后面

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容