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



posted @ 2018-05-09 22:35  saintdingtheGreat  阅读(136)  评论(0编辑  收藏  举报