zoukankan      html  css  js  c++  java
  • 常见数据库优化方案(十二)

    数据库循环、触发器、队列、事务、外键

    一、数据库循环
    循环 LOOP
    DECLARE  x number;

    BEGIN 

    x := 0;

    <<repeat_loop>>[跳转标志]

    x := x + 1; 

    [代码块]

    IF x < 9 THEN[跳转限制]

    GOTO repeat_loop;[跳转标志]

    END IF;

    END;

    循环 FOR
    DECLARE  x number; --声明变量

    BEGIN 

    x := 1; --给初值 

    FOR x IN [REVERSE] 1 .. 10 LOOP    --reverse由大到小   

    [代码块]

    END LOOP; 
    END;
    REVERSE:反向,默认正向
    循环 WHILE
    DECLARE  x number;

    BEGIN

    x := 0;[循环初始条件]

    WHILE x < 9 LOOP[循环控制]

    x := x + 1;[循环自增]

    [代码块]

    END LOOP;

    END;

    循环 LOOP

    DECLARE  x number;

    BEGIN

    x := 0;

    LOOP[循环标志]

    x := x + 1;[循环自增]

    EXIT WHEN x > 9;[循环控制]

    [代码块]

    END LOOP;

    END;

    Mysql循环:https://www.cnblogs.com/ClassNotFoundException/p/6369843.html

    二、触发器

    触发器分为行级触发器和语句级触发器

    前者每操作一行执行一次,后者每执行一次语句执行一次

    语法

    CREATE TRIGGER trigger_name

    [DEFINER = { user | CURRENT_USER }] – 触发器

    ON {table_name | view_name}

    {FOR | After | Instead of } [ insert, update,delete ]

    AS          

    sql_statement

    FOR EACH ROW :行级触发器

    例:

    CREATE

        TRIGGER trigger_testname

        AFTER  DELETE

        ON file FOR EACH ROW

        UPDATE file_txt

             set file_name = 'GG',

                     display_name = 'xx'

         WHERE file_id = 1;
    删除触发器
    drop trigger [trigger_name];

    https://www.cnblogs.com/yank/p/4193820.html

    https://blog.csdn.net/goskalrie/article/details/53020631
    http://www.jb51.net/article/30164.htm


    三、队列
    如果数据库返回信息的接收者不可用,或者产生延迟是,将数据库返回的信息保存到消息队列,直到可以成功的传递信息。这种技术可以在高并发中避免对数据库造成巨大的压力,减少了数据库响应延迟。显著改善用户响应延迟。对数据库访问峰值有很好的削峰作用。
    Mysql数据库队列实现
    https://www.cnblogs.com/archy_yu/p/5794118.html

    Oracle数据库队列实现
    https://blog.csdn.net/hj402555749/article/details/8549515
    https://www.cnblogs.com/BradMiller/archive/2011/01/26/1945718.html


    数据库队列常用于处理并发访问 – 电商
    并发访问:操作加锁、事务原子性等

    队列 使用 redis数据库 并发数据库

    创建:
    SET FOREIGN_KEY_CHECKS=0;
    -- ----------------------------
    -- Table structure for unsent_emails
    -- ----------------------------
    DROP TABLE IF EXISTS `unsent_emails`;
    CREATE TABLE `unsent_emails` (
      `ID` int(11) NOT NULL AUTO_INCREMENT,
      `STATUS` enum('unsent','claimed','sent') NOT NULL,
      `OWNER` int(11) NOT NULL DEFAULT '0',
      `ts` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
      PRIMARY KEY (`ID`),
      KEY `STATUS` (`STATUS`),
      KEY `OWNER` (`OWNER`),
      KEY `ts` (`ts`)
    ) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='mysql实现队列表';

    两种标记待处理数据的方式
    第一种: select for update模式
    begin;
    select id from unsent_emails
        where owner = 0 and status = 'unsent'
        limit 10 for update;
    -- result 10,20,33
    update unsent_emails
        set status = 'claimed',owner = CONNECTION_ID()
        where id in (10,20,33);
    commit;
    第二种:update then select模式
    set autocommit=1;
    commit;
    update unsent_emails
        set STATUS = 'claimed',owner = CONNECTION_ID()
        where owner = 0 and STATUS = 'unsent'
        limit 10;
    set autocommit=0;
    select id from unsent_emails
        where owner = CONNECTION_ID() and status = 'claimed';

    CONNECTION_ID() 用于查看当前用户的连接数

     SHOW PROCESSLIST;        # 查看当前用户的连接信息

    (1) Id :用户登录 MySQL 时,系统分配的连接 id
    (2) User :当前连接的用户
    (3) Host :显示这个语句是从哪个 IP 的哪个端口上发出的,可以用来追踪出现问题语句的用户
    (4) db :显示这个进程目前连接的是哪个数据库
    (5) Command :显示当前连接执行的命令,一般取值为休眠(Sleep)、查询(Query)、连接(Connect)
    (6) Time :显示这个状态持续的时间,单位是秒
    (7) State :显示使用当前连接的 SQL 语句的状态
    (8) Info :显示这个 SQL 语句
    这样我们就可以实现对数据库访问操作的队列式管理

    select for update的模式的加锁会增加多个消费队列的竞争问题。

    为避免僵尸任务的产生

    所以我们还是需要一个新的定时器或者线程来定时检测并且update,将那些僵尸任务的记录更新到原始状态,就可以了。
    僵尸任务的定义必须符合两点,1:任务被搁置了很久,比如十分钟,而通常一个任务只需要10秒就可以处理完;2:任务的owner(线程id或者连接id)已经不存在,只需要执行show processlist就可以获取当前正在工作的线程id了。代码如下

    update unsent_emails
        set owner = 0,status = 'unsent'
        where owner not in (10,20,33,44) and status = 'claimed'
        and ts < current_timestamp - interval 10minute;

    强烈推荐看一下这篇文章真是赞 一个基于mysql构建的队列表



    四、外键
    作用:保持数据的一致性、完整性。设置外键在数据库中定义两张表之间的关系,如果不设置外键的话,仅仅是你认为两部分数据有关系。但是数据库并不这么认为。当你对数据表进行插入删除修改操作时,数据库并不会对修改数据进行关系检查



    不设置外键的情况下。学生成绩表的学号字段和学生信息表的学号字段是没有关联的。仅仅是你自己觉得他们有关系而已。数据库并 不觉得它俩有关系。也就是说,你在学生成绩表的学号字段插了一个值(比方20140999999),可是这个值在学生信息表中并没有,这个时候,数据库还是允 许你插入的,它并不会对插入的数据做关系检查。然而在设置外键的情况下。你插入学生成绩表学号字段的值必需要求在学生信息表的学号字段能找到。 同一时候。假设你要删除学生信息表的某个学号字段。必须保证学生成绩表中没有引用该字段值的列,否则就没法删除。
    这就是所谓的保持数据的一致性和完整性。你想。如 果学生成绩表还引用学生信息表的某个学号,你却把学生信息表中的这个学号删了,学生成绩表就不知道这个学号相应的学生是哪个学生。

    数据的一致性还包含数据类型的一致性(这 个见以下就知道了)。

    外键的使用规范
    从表的字段必须与外键类型同样(如上。分数表 stu 的类型必须和学生表 sid 的类型同样,比方都是 int(10) 类型)
    外键必须是主表的唯一键(如上。学生表 sid 是主键,而主键是唯一的。所以能够作为分数表 stu 的外键)
    有关联的字段(如上,分数表之所以使用学生表的 sid 是由于两者有关联,分数表记录的是学生的分数,而学生能够用 sid 来唯 一标识)
    避免使用复合键(也就是说从表能够同一时候引用多个外表的字段作为一个外键,一般不推荐这样的做法)




    五、数据库并发访问、事务与锁的关系
    事务定义:事务是作为单个逻辑单元工作执行的一系列操作。可以是一条 sql 语句,也可以是多条 sql 语句 ( 这是它的描述性定义 )
    事务特性:
    原子性 (Atomic) :指整个数据库事务是不可分割的工作单位。
    一致性 (Consistency) :指数据库事务不能破坏关系数据的完整性以及业务逻辑的一致性。
    隔离性 (Isolation) :指的是在并发环境中,当不同的事务同时操作相同的数据时,每个事务都有各自的完整数据空间。
    持久性 (Durability) :指的是只要事务成功结束,它对数据库所做的更改就必须永久保存下来。

    数据库使用日志来保证事务的原子性、一致性和持久性。日志记录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更改,使数据库退回到执行事务前的初始状态
    数据库使用锁机制来保证事务的隔离性,拥有各自的独立空间

    痛苦预示着超脱
  • 相关阅读:
    python_捕获异常
    requests二次封装_捕获异常
    python_flask模块
    python_redis模块
    python_requests模块
    使用pstack和gdb调试死锁
    如何编写go代码
    GDB调试命令手册
    core文件相关
    shared_ptr的线程安全性
  • 原文地址:https://www.cnblogs.com/supperlhg/p/9149057.html
Copyright © 2011-2022 走看看