zoukankan      html  css  js  c++  java
  • mysql你问我答

    1.尊敬的先生,请您谈谈mysql数据库的引擎

    数据库中的表设定了什么存储引擎,那么该表在数据存储方式、数据更新方式、数据查询性能以及是否支持索引等方面就会有不同的“效果”。

    mysql引擎大致分两类:

    InnoDB:支持事务:

      可以实现表锁:select * from tb for update;

      还可以实现行锁:select id,name from tb where id=2 for update ;

    Myisam:支持全文索引:

      特点是查询速度快:

      也支持表锁;select * from tb for update;

    2.请您写出创建外键的语句

    例子援引自  https://my.oschina.net/sallency/blog/465079

    //学生表 cid作为外键关联班级表 pid作为 档案表外键的关联 所以这俩货都得有索引
    create table my_student(
    `id` int unsigned not null auto_increment primary key,
    `name` varchar(25) not null comment 'student name',
    `pid` int unsigned not null comment 'student profile id',
    `cid` int unsigned not null comment 'student class id',
    key `cid`(`cid`),
    key `pid`(`pid`)
    )engine=InnoDB default charset=utf8 auto_increment=1;

    //班级表 id作为 学生表外键的关联 已为主键索引
    create table my_class(
    `id` int unsigned not null auto_increment primary key,
    `cname` varchar(25) not null comment 'class name',
    `info` tinytext not null default ''
    )engine=InnoDB default charset=utf8 auto_increment=1;

    添加外键   alter table my_profile  add constraint profile_student foreign key (`id`)  references my_student(`pid`) on delete cascade on update no action;

     

    3.请您写出语句阐明多对多的关系:援引自 https://www.cnblogs.com/ugfly/p/7739182.html

    create table course (
    id int primary key auto_increment,
    name varchar(20),
    teacher_id int unique,
    foreign key(teacher_id) references teacher(id)
    );

    create table student (
    id int primary key into_increment,
    name varchar(20),
    sex enum('male','famale') default 'male',
    class_id int,
    foreign key(class_id) references class(id)
    );

     

    create table student2course (
    id int primary key auto_increment,
    student_id int,
    course_id int,
    foreign key(student_id) references student(id)
    on delete cascade
    on update cascade,
    foreign key(course_id) references course(id)
    on delete cascade
    on update cascade,
    score int
    );

    4.可能的笔试题----mysql数据查询疯狂41例

    http://www.cnblogs.com/saintdingspage/p/9017370.html

    5.mysql其他重要知识点:援引自https://www.cnblogs.com/OldJack/p/6973579.html#t2

    下列数据结构都保存在数据库中

    • 触发器

    对某个表进行【增/删/改】操作的前后如果希望触发某个特定的行为时,可以使用触发器,触发器用于定制用户对表的行进行【增/删/改】前后的行为。

    不过触发器性能不高!

      

    -- 插入前
    CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    -- 插入后
    CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    -- 删除前
    CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    -- 删除后
    CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    -- 更新前
    CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    -- 更新后
    CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END

    插入前触发器

    delimiter //
    CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
    BEGIN
    
    IF NEW. NAME = 'alex' THEN
        INSERT INTO tb2 (NAME)
    VALUES
        ('aa');
    END IF;
    END //
    delimiter ;

    插入后触发器

    CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW
    BEGIN
        IF NEW. num = 666 THEN
            INSERT INTO tb2 (NAME)
            VALUES
                ('666'),
                ('666') ;
        ELSEIF NEW. num = 555 THEN
            INSERT INTO tb2 (NAME)
            VALUES
                ('555'),
                ('555') ;
        END IF;
    END//
    delimiter ;

    特别的:NEW表示即将插入的数据行,OLD表示即将删除的数据行。

    2. 删除触发器

    DROP TRIGGER tri_after_insert_tb1;

    3. 使用触发器

    触发器无法由用户直接调用,而只由对表的【增/删/改】操作被动引发。

    insert into tb1(num) values(666);

    存储过程是一个SQL语句集合,当主动去调用存储过程时,其中内部的SQL语句会按照逻辑执行。

    1. 创建存储过程

    复制代码
    -- 创建存储过程  无参数存储过程
    
    delimiter //
    create procedure p1()
    BEGIN
        select * from t1;
    END//
    delimiter;
    
    
    
    -- 执行存储过程  
    
    call p1();
    复制代码

    对于存储过程,可以接收参数,其参数有三类:

    • in          仅用于传入参数用
    • out        仅用于返回值用
    • inout     既可以传入又可以当作返回值
    复制代码
    -- 创建存储过程  有参数的存储过程
    delimiter \
    create procedure p1(
        in i1 int,
        in i2 int,
        inout i3 int,
        out r1 int
    )
    BEGIN
        DECLARE temp1 int;
        DECLARE temp2 int default 0;
        
        set temp1 = 1;
    
        set r1 = i1 + i2 + temp1 + temp2;
        
        set i3 = i3 + 100;
    
    end\
    delimiter ;
    
    -- 执行存储过程
    set @t1 =4;
    set @t2 = 0;
    CALL p1 (1, 2 ,@t1, @t2);
    SELECT @t1,@t2;
    复制代码

    应用:

    a. 获得结果集

    delimiter //
    create procedure p1()
    begin
        select * from v1;
    end //
     delimiter ;

    b. 获得结果集+out值

    复制代码
    delimiter //
    create procedure p2(
        in n1 int,
        inout n3 int,
        out n2 int,
        )
    begin
        declare temp1 int ;
        declare temp2 int default 0;
    
        select * from v1;
        set n2 = n1 + 100;
        set n3 = n3 + n1 + 100;
    end //
    delimiter ;
    复制代码

    c. 事务

    复制代码
    delimiter \
    CREATE PROCEDURE p1 (OUT p_return_code TINYINT)
    BEGIN
        DECLARE
            EXIT HANDLER FOR SQLEXCEPTION
        BEGIN
            -- ERROR 
        SET p_return_code = 1 ; ROLLBACK ;
        END ; DECLARE
            EXIT HANDLER FOR SQLWARNING
        BEGIN
            -- WARNING 
        SET p_return_code = 2 ; ROLLBACK ;
        END ; START TRANSACTION ; DELETE
        FROM
            tb1 ; INSERT INTO tb2 (NAME)
        VALUES
            ('seven') ; COMMIT ; -- SUCCESS 
        SET p_return_code = 0 ;
        END\
    
    delimiter ;
    复制代码

    d. 游标 cursor

    复制代码
    delimiter //
    CREATE PROCEDURE p3 ()
    BEGIN
        DECLARE
            ssid INT ; -- 自定义变量1  
            DECLARE
                ssname VARCHAR (50) ; -- 自定义变量2  
                DECLARE
                    done INT DEFAULT FALSE ; DECLARE
                        my_cursor CURSOR FOR SELECT
                            sid,
                            sname
                        FROM
                            student ; DECLARE
                                CONTINUE HANDLER FOR NOT FOUND
                            SET done = TRUE ; OPEN my_cursor ; xxoo :
                            LOOP
                                FETCH my_cursor INTO ssid,
                                ssname ;
                            IF done THEN
                                LEAVE xxoo ;
                            END
                            IF ; INSERT INTO teacher (tname)
                            VALUES
                                (ssname) ;
                            END
                            LOOP
                                xxoo ; CLOSE my_cursor ;
    END//
    
    delimter ;
    复制代码

    e. 动态执行SQL

    复制代码
    delimiter \
    CREATE PROCEDURE p4 (IN nid INT)
    BEGIN
        PREPARE prod
    FROM
        'select * from student where sid > ?' ; 
       EXECUTE prod USING @nid ;
       DEALLOCATE PREPARE prod ; END\ delimiter ;
    复制代码

    2. 删除存储过程

    drop procedure proc_name;

    3. 执行存储过程

    若执行存储过程前,该存储过程已被修改,则不会应用最新修改,需要重新建立存储过程,或将原存储过程删除后重新运行定义部分

    复制代码
    -- 无参数
    call proc_name();
    
    -- 有参数,全in
    call proc_name(1,2);
    
    -- 有参数,有in,out,inout
    set @t1=0;
    set @t2=3;
    call proc_name(1,2,@t1,@t2);
    复制代码

    6.mysql常用内置函数 

    7.索引相关 援引自http://www.cnblogs.com/wupeiqi/articles/5716963.html

    7.1、索引
      索引是表的目录,在查找内容之前可以先在目录中查找索引位置,以此快速定位查询数据。对于索引,会保存在额外的文件中。

    7.2、索引种类

    普通索引:仅加速查询
    唯一索引:加速查询 + 列值唯一(可以有null)
    主键索引:加速查询 + 列值唯一 + 表中只有一个(不可以有null)
    组合索引:多列值组成一个索引,
    专门用于组合搜索,其效率大于索引合并
    全文索引:对文本的内容进行分词,进行搜索
    索引合并,使用多个单列索引组合搜索
    覆盖索引,select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖

    7.3、相关命令

    - 查看表结构
    desc 表名

    - 查看生成表的SQL
    show create table 表名

    - 查看索引
    show index from 表名

    - 查看执行时间
    set profiling = 1;
    SQL...
    show profiles;

    7.4、使用索引和不使用索引

    由于索引是专门用于加速搜索而生,所以加上索引之后,查询效率会快到飞起来。

    # 有索引
    mysql> select * from tb1 where name = 'wupeiqi-888';
    +-----+-------------+---------------------+----------------------------------+---------------------+
    | nid | name | email | radom | ctime |
    +-----+-------------+---------------------+----------------------------------+---------------------+
    | 889 | wupeiqi-888 | wupeiqi888@live.com | 5312269e76a16a90b8a8301d5314204b | 2016-08-03 09:33:35 |
    +-----+-------------+---------------------+----------------------------------+---------------------+
    1 row in set (0.00 sec)

    # 无索引
    mysql> select * from tb1 where email = 'wupeiqi888@live.com';
    +-----+-------------+---------------------+----------------------------------+---------------------+
    | nid | name | email | radom | ctime |
    +-----+-------------+---------------------+----------------------------------+---------------------+
    | 889 | wupeiqi-888 | wupeiqi888@live.com | 5312269e76a16a90b8a8301d5314204b | 2016-08-03 09:33:35 |
    +-----+-------------+---------------------+----------------------------------+---------------------+
    1 row in set (1.23 sec)


    7-5、正确使用索引

    数据库表中添加索引后确实会让查询速度起飞,但前提必须是正确的使用索引来查询,如果以错误的方式使用,则即使建立索引也会不奏效。
    即使建立索引,索引也不会生效:

    - like '%xx'
    select * from tb1 where name like '%cn';
    - 使用函数
    select * from tb1 where reverse(name) = 'wupeiqi';
    - or
    select * from tb1 where nid = 1 or email = 'seven@live.com';
    特别的:当or条件中有未建立索引的列才失效,以下会走索引
    select * from tb1 where nid = 1 or name = 'seven';
    select * from tb1 where nid = 1 or email = 'seven@live.com' and name = 'alex'
    - 类型不一致
    如果列是字符串类型,传入条件是必须用引号引起来,不然...
    select * from tb1 where name = 999;
    - !=
    select * from tb1 where name != 'alex'
    特别的:如果是主键,则还是会走索引
    select * from tb1 where nid != 123
    - >
    select * from tb1 where name > 'alex'
    特别的:如果是主键或索引是整数类型,则还是会走索引
    select * from tb1 where nid > 123
    select * from tb1 where num > 123
    - order by
    select email from tb1 order by name desc;
    当根据索引排序时候,选择的映射如果不是索引,则不走索引
    特别的:如果对主键排序,则还是走索引:
    select * from tb1 order by nid desc;

    - 组合索引最左前缀
    如果组合索引为:(name,email)
    name and email -- 使用索引
    name -- 使用索引
    email -- 不使用索引


    7.6、其他注意事项

    - 避免使用select *
    - count(1)或count(列) 代替 count(*)
    - 创建表时尽量时 char 代替 varchar
    - 表的字段顺序固定长度的字段优先
    - 组合索引代替多个单列索引(经常使用多个条件查询时)
    - 尽量使用短索引
    - 使用连接(JOIN)来代替子查询(Sub-Queries)
    - 连表时注意条件类型需一致
    - 索引散列值(重复少)不适合建索引,例:性别不适合

    -创建表,把固定长度的往前放,char是定长,varchar长度是自增长
    -如果字段的值相对固定,则待选值可以融入数据库列的设置,---相当于把数据放入内存,也能提高查询速度!否则你将不得不用到连接查询!
    -尽量避免全表搜索

    8.开启慢日志查询的办法 

    slow_query_log = ON 是否开启慢日志记录
    long_query_time = 2 时间限制,超过此时间,则记录
    slow_query_log_file = /usr/slow.log 日志文件
    log_queries_not_using_indexes = ON 为使用索引的搜索是否记录

    9.执行计划

    explain + 查询SQL - 用于显示SQL执行信息参数,根据参考信息可以进行SQL优化

    mysql> explain select from tb2;
    +----+-------------+-------+------+---------------+------+---------+------+------+-------+
    | id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------+
    |  1 | SIMPLE      | tb2   | ALL  NULL          NULL NULL    NULL |    2 | NULL  |
    +----+-------------+-------+------+---------------+------+---------+------+------+-------+
    1 row in set (0.00 sec)

    10.导入和导出的mysql命令

    不管是Oracle数据库还是SQL Server数据库,每个数据库都有自己的一套数据备份和恢复的方法,MySQL数据库也不例外。MySQL数据库备份和恢复用到了两个命令,分别是“mysqldump”和“mysql”,我们使用“mysqldump”命令进行数据库备份,使用“mysql”命令对数据库进行数据恢复。

    语法一、导出数据库中所有表结构;只导出表结构, 不导出表中的数据

    mysqldump --opt -d 数据库名称 -u用户名 -p密码 > 保存文件路径

    语法二、导出数据库中所有表中的数据;只导出表中的数据,不导出表结构

    mysqldump -t 数据库名称 -u用户名 -p密码 > 保存文件路径

    语法三、导出数据库中所有的表结构和数据;导出表结构和数据

    mysqldump 数据库名称 -u用户名 -p密码 > 保存文件路径

    语法四、导出指定表的结构和数据

    mysqldump -u用户名 -p密码 -B 数据库名称 --table 表名 > 保存文件路径

    语法五、导出指定表数据,只导出数据,不导出表结构

    mysqldump -t 数据库名称 -u用户名 -p密码 --table 表名 > 保存文件路径

    语法六、将备份文件导入到数据库

    mysql -u用户名 -p密码 数据库名称 < 用于恢复数据库的数据文件路径

     

    11.请您谈谈对海量数据的分页意见

    问题:往后翻页的时候,会对数据表进行扫描,从而把所有的分页扫描一遍

    • 先查主键,在分页。
      • select * from tb where id in (
      • select id from tb where limit 10 offset 30
      • )
    • 按照业务需求是否可以设置只让用户看200页(假如客户不看历史数据)
    • 记录当前页 数据ID最大值和最小值(上一页下一页)

    在翻页时,根据条件先进行筛选;筛选完毕之后,再根据limit offset 查询。

    select * from (select * from tb where id > 22222222) as B limit 10 offset 0

    如果用户自己修改页码,也可能导致慢;此时对url种的页码进行加密(可以参考rest framework 的分页,对url进行加密,开发时对这种url进行解密开发)。

    • 如果在海量数据中只想获得一条数据,则可以如下操作 select * from coachinfo where name = 'xuxiaodong' limit 1



  • 相关阅读:
    apache2.4+php7.3.2+mysql5.7
    redis 中的key值过期后,触发通知事件
    zookeeper之分布式锁以及分布式计数器(通过curator框架实现)
    SpringCloud学习笔记(4)——Zuul
    SpringCloud学习笔记(3)——Hystrix
    SpringCloud学习笔记(2)——Ribbon
    c++各种排序的简单实现
    c++动态规划dp算法题
    华为机试练习
    ubuntu遇到的 the system is runing low-graphics mode 问题
  • 原文地址:https://www.cnblogs.com/saintdingspage/p/9017095.html
Copyright © 2011-2022 走看看