3. MyAQL数据库|Navicat工具与pymysql模块 | 内置功能 | 索引原理

1、Navicat工具与pymysql模块

在生产环境中操作MySQL数据库还是推荐使用命令行工具mysql,但在我们自己开发测试时,可以使用可视化工具Navicat,以图形界面的形式操作MySQL数据库
复制代码
掌握:
#1. 测试+链接数据库
#2. 新建库
#3. 新建表,新增字段+类型+约束
#4. 设计表:外键
#5. 新建查询
#6. 备份库/表

#注意:
批量加注释:ctrl+?键
批量去注释:ctrl+shift+?键
复制代码

之前我们都是通过MySQL自带的命令行客户端工具mysql来操作数据库,那如何在python程序中操作数据库呢?这就用到了pymysql模块,该模块本质就是一个套接字客户端软件,使用前需要事先安装   pip3 install pymysql

准备账号、表

用cmd授权一个账号

复制代码
C:\Users\Administrator>mysql -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 12
Server version: 5.6.39 MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> grant all on *.* to 'root'@'%' identified by '123';
Query OK, 0 rows affected (0.07 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.12 sec)
复制代码

查看IP地址:

在管理员权限下运行cmd,输入ipconfig 

IPv4 地址 . . . . . . . . . . . . : 192.168.1.123

复制代码

import pymysql

user=input('user>>: ').strip()
pwd=input('password>>: ').strip()

# 建立链接
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿到游标
cursor=conn.cursor()

# 执行sql语句
# sql='select * from userinfo where user = "%s" and pwd="%s"' %(user,pwd)
# print(sql)

sql='select * from userinfo where user = %s and pwd=%s'
rows=cursor.execute(sql,(user,pwd)) #提交给游标执行  execute这个接口拿到的是2 rows in set (0.00 sec) 2那个行数,如果值不为0说明就输对了

cursor.close()
conn.close()

# 进行判断
if rows:
    print('登录成功')
else:
    print('登录失败')
复制代码

 

mysql语句中 -- xfjl ,--+空格后边的都给你注释掉了

复制代码
import pymysql

user=input('user>>: ').strip()
pwd=input('password>>: ').strip()

# 建立链接
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿到游标
cursor=conn.cursor()

# 执行sql语句
sql='select * from userinfo where user = "%s" and pwd="%s"' %(user,pwd)
print(sql)
rows=cursor.execute(sql)

#sql='select * from userinfo where user = %s and pwd=%s'
#由execute作为拼接,不用你自己去拼接了,在拼接过程中给你过滤掉这种非法操作
#rows=cursor.execute(sql,(user,pwd)) #提交给游标执行  execute这个接口拿到的是2 rows in set (0.00 sec) 2那个行数,如果值不为0说明就输对了

cursor.close()
conn.close()

# 进行判断
if rows:
    print('登录成功')
else:
    print('登录失败')

打印: #两种执行的错误
user>>: egon" -- xxxhhhh
password>>: 
select * from userinfo where user = "egon" -- xxxhhhh" and pwd=""
登录成功


user>>: xxxx" or 1=1 -- hhhhhaaa
password>>: 
select * from userinfo where user = "xxxx" or 1=1 -- hhhhhaaa" and pwd=""
登录成功
复制代码

改正:

复制代码
import pymysql

user=input('user>>: ').strip()
pwd=input('password>>: ').strip()

# 建立链接
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿到游标
cursor=conn.cursor()

# 执行sql语句
# sql='select * from userinfo where user = "%s" and pwd="%s"' %(user,pwd)
# print(sql)
# rows=cursor.execute(sql)

sql='select * from userinfo where user = %s and pwd=%s'
#由execute作为拼接,不用你自己去拼接了,在拼接过程中给你过滤掉这种非法操作
rows=cursor.execute(sql,(user,pwd)) #提交给游标执行  execute这个接口拿到的是2 rows in set (0.00 sec) 2那个行数,如果值不为0说明就输对了

cursor.close()
conn.close()

# 进行判断
if rows:
    print('登录成功')
else:
    print('登录失败')
复制代码

增加

复制代码
import pymysql

# 建立链接
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿游标
cursor=conn.cursor()

# 执行sql
# 增、删、改  对数据的变动
sql='insert into userinfo(user,pwd) values(%s,%s)'
rows=cursor.execute(sql,('wxx','123'))
print(rows)


conn.commit() #必须加上这个
# 关闭
cursor.close()
conn.close()

打印:
1
复制代码
复制代码
#1、增删改
import pymysql

# 建立链接
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿游标
cursor=conn.cursor()

# 执行sql
# 增、删、改  对数据的变动
sql='insert into userinfo(user,pwd) values(%s,%s)'
# rows=cursor.execute(sql,('wxx','123'))
# print(rows)
rows=cursor.executemany(sql,[('yxx','123'),('egon1','111'),('egon2','2222')]) #可以插入多条
print(rows)

conn.commit() #必须加上这个
# 关闭
cursor.close()
conn.close()

打印
3
复制代码

 

 

复制代码
#2、查询
import pymysql
# # 建立链接
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)

# 拿游标
cursor=conn.cursor(pymysql.cursors.DictCursor) #基于字典形式的游标,不加括号内的是以元组形式

# 执行sql
# 查询
rows=cursor.execute('select * from userinfo;') #把字符串send给服务端,在服务端把这个sql语句执行下,然后把结果丢给客户端
print(rows)
# print(cursor.fetchone()) #代表取一行
# print(cursor.fetchone())
# print(cursor.fetchone())
# print(cursor.fetchone())
# print(cursor.fetchone())
# print(cursor.fetchone())
# print(cursor.fetchone())

#print(cursor.fetchmany(2)) #指定取的个数,以列表的形式

#print(cursor.fetchall()) #拿出所有,列表的形式
# print(cursor.fetchall())

cursor.scroll(3,mode='absolute') #移动光标 相对绝对位置移动,从头数3个开始取出来1个,结果是第4个
#print(cursor.fetchone())
cursor.scroll(2,mode='relative') # 相对当前位置移动 往后跳2位
print(cursor.fetchone())
# 关闭
cursor.close()
conn.close()

打印:
6
{'id': 6, 'user': 'egon2', 'pwd': '2222'}
复制代码

 

复制代码
import pymysql
#
# # 建立链接
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db10',
    charset='utf8'
)
#
# # 拿游标
cursor=conn.cursor()

sql='insert into userinfo(user,pwd) values(%s,%s)'

rows=cursor.executemany(sql,[('egon3','123'),('egon4','111'),('egon5','2222')])
print(cursor.lastrowid) #插入之前光标走到哪里了
#
conn.commit() #必须加上这个
# 关闭
cursor.close()
conn.close()

打印:
7
复制代码

涉及数据库的操作的,先要编写好数据,然后基于pymysql模块帮我把sql语句提交给mysql服户端,执行完之后把结果再返回到应用程序中再做进一步的处理;将应用程序的开发与数据库的开发结合

2、mysql内置函数功能

  视图是一个虚拟表(非真实存在),其本质是【根据SQL语句获取动态的数据集,并为其命名】,用户使用时只需使用【名称】即可获取结果集,可以将该结果集当做表来使用。

  使用视图我们可以把查询过程中的临时表摘出来,用视图去实现,这样以后再想操作该临时表的数据时就无需重写复杂的sql了,直接去视图中查找即可,但视图有明显地效率问题,并且视图是存放在数据库中的,如果我们程序中使用的sql过分依赖数据库中的视图,即强耦合,那就意味着扩展sql极为不便,因此并不推荐使用

  视图 只有表结构frm,没有数据,因为是查出来的虚拟表;不用重复写,但是不建议使用,如果有好多个视图,要找到所有的视图给它修改很麻烦;

复制代码
mysql> use db7;
Database changed
mysql> select * from course;
+-----+--------+------------+
| cid | cname  | teacher_id |
+-----+--------+------------+
|   1 | 生物   |          1 |
|   2 | 物理   |          2 |
|   3 | 体育   |          3 |
|   4 | 美术   |          2 |
+-----+--------+------------+
4 rows in set (0.00 sec)

mysql> select * from teacher;
+-----+-----------------+
| tid | tname           |
+-----+-----------------+
|   1 | 张磊老师        |
|   2 | 李平老师        |
|   3 | 刘海燕老师      |
|   4 | 朱云海老师      |
|   5 | alex            |
+-----+-----------------+
5 rows in set (0.00 sec)

mysql> select * from course inner join teacher on course.teacher_id=teacher.tid;
+-----+--------+------------+-----+-----------------+
| cid | cname  | teacher_id | tid | tname           |
+-----+--------+------------+-----+-----------------+
|   1 | 生物   |          1 |   1 | 张磊老师        |
|   2 | 物理   |          2 |   2 | 李平老师        |
|   4 | 美术   |          2 |   2 | 李平老师        |
|   3 | 体育   |          3 |   3 | 刘海燕老师      |
+-----+--------+------------+-----+-----------------+
4 rows in set (0.10 sec)

mysql> create view course2teacher as select * from course inner join teacher on course.teacher_id=teacher.tid;
Query OK, 0 rows affected (0.20 sec)

mysql> show tables;
+----------------+
| Tables_in_db7  |
+----------------+
| course         |
| course2teacher |
| teacher        |
+----------------+
3 rows in set (0.00 sec)

mysql>
复制代码

 

触发器

使用触发器可以定制用户对表进行【增、删、改】操作时前后的行为,注意:没有查询

复制代码
mysql> create database db11;
Query OK, 1 row affected (0.00 sec)

mysql> use db11;
Database changed
mysql> CREATE TABLE cmd (
    ->     id INT PRIMARY KEY auto_increment,
    ->     USER CHAR (32),
    ->     priv CHAR (10),
    ->     cmd CHAR (64),
    ->     sub_time datetime, #提交时间
    ->     success enum ('yes', 'no') #0代表执行失败
    -> );
Query OK, 0 rows affected (0.77 sec)

mysql>
mysql> CREATE TABLE errlog (
    ->     id INT PRIMARY KEY auto_increment,
    ->     err_cmd CHAR (64),
    ->     err_time datetime
    -> );
Query OK, 0 rows affected (0.68 sec)

#创建触发器 mysql
> delimiter // mysql> CREATE TRIGGER tri_after_insert_cmd AFTER INSERT ON cmd FOR EACH ROW -> BEGIN -> IF NEW.success = 'no' THEN #等值判断只有一个等号 -> INSERT INTO errlog(err_cmd, err_time) VALUES(NEW.cmd, NEW.sub_time) ; #必须加分号 -> END IF ; #必须加分号 -> END// Query OK, 0 rows affected (0.34 sec) mysql> delimiter ; mysql> mysql> mysql>#往cmd中插入记录,触动触发器,根据IF条件决定是否插入错误日志 mysql> INSERT INTO cmd ( -> USER, -> priv, -> cmd, -> sub_time, -> success -> ) -> VALUES -> ('egon','0755','ls -l /etc',NOW(),'yes'), -> ('egon','0755','cat /etc/passwd',NOW(),'no'), -> ('egon','0755','useradd xxx',NOW(),'no'), -> ('egon','0755','ps aux',NOW(),'yes'); Query OK, 4 rows affected (0.43 sec) Records: 4 Duplicates: 0 Warnings: 0 mysql> select * from cmd; +----+------+------+-----------------+---------------------+---------+ | id | USER | priv | cmd | sub_time | success | +----+------+------+-----------------+---------------------+---------+ | 1 | egon | 0755 | ls -l /etc | 2018-04-28 18:26:33 | yes | | 2 | egon | 0755 | cat /etc/passwd | 2018-04-28 18:26:33 | no | | 3 | egon | 0755 | useradd xxx | 2018-04-28 18:26:33 | no | | 4 | egon | 0755 | ps aux | 2018-04-28 18:26:33 | yes | +----+------+------+-----------------+---------------------+---------+ 4 rows in set (0.00 sec) mysql> select * from errlog; #查询错误日志发现有两条 +----+-----------------+---------------------+ | id | err_cmd | err_time | +----+-----------------+---------------------+ | 1 | cat /etc/passwd | 2018-04-28 18:26:33 | | 2 | useradd xxx | 2018-04-28 18:26:33 | +----+-----------------+---------------------+ 2 rows in set (0.00 sec)
复制代码

存储过程

把mysql处理好的数据给封装好,一个接口名,应用程序可以直接调用接口,这个接口就叫储存过程。是mysql内置功能的一系列总和;

存储过程包含了一系列可执行的sql语句,存储过程存放于MySQL中,通过调用它的名字可以执行其内部的一堆sql

使用存储过程的优点:

1. 用于替代程序写的SQL语句,实现程序与sql解耦

2. 基于网络传输,传别名的数据量小,而直接传sql数据量大

使用存储过程的缺点:

1. 程序员扩展功能不方便

程序与数据库结合使用的三种方式:

复制代码
#方式一:
    MySQL:存储过程
    程序:调用存储过程
#方式二:
    MySQL:
    程序:纯SQL语句
#方式三:
    MySQL:
    程序:类和对象,即ORM(本质还是纯SQL语句)
复制代码

创建简单的存储过程:

#1、无参存储过程
    delimiter //
    create procedure p1()
    BEGIN
        select * from db7.teacher;
    END //
    delimiter ;
复制代码
mysql> use db7;
Database changed
mysql> delimiter //
mysql> create procedure p1()
    -> BEGIN
    -> select * from db7.teacher;
    -> END //
Query OK, 0 rows affected (0.21 sec)

mysql> delimiter ;
mysql>
mysql>
mysql> show create procedure p1;
+-----------+--------------------------------------------+-----------------------------------------------------------------------------------------+----------------------+----------------------+------
--------------+
| Procedure | sql_mode                                   | Create Procedure                                                                        | character_set_client | collation_connection | Datab
ase Collation |
+-----------+--------------------------------------------+-----------------------------------------------------------------------------------------+----------------------+----------------------+------
--------------+
| p1        | STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION | CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`()
BEGIN
select * from db7.teacher;
END | utf8                 | utf8_general_ci      | utf8_general_ci    |
+-----------+--------------------------------------------+-----------------------------------------------------------------------------------------+----------------------+----------------------+------
--------------+
1 row in set (0.00 sec)
复制代码

    # MySQL中调用
    call p1();
复制代码
mysql> call p1();
+-----+-----------------+
| tid | tname           |
+-----+-----------------+
|   1 | 张磊老师        |
|   2 | 李平老师        |
|   3 | 刘海燕老师      |
|   4 | 朱云海老师      |
|   5 | alex            |
+-----+-----------------+
5 rows in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)
复制代码

    # Python中调用
    cursor.callproc('p1') #调用存储过程
复制代码
import pymysql

# 建立链接
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db7',
    charset='utf8'
)

# 拿游标
cursor=conn.cursor()

# 执行sql
cursor.callproc('p1') #只是执行
print(cursor.fetchall())

打印
((1, '张磊老师'), (2, '李平老师'), (3, '刘海燕老师'), (4, '朱云海老师'), (5, 'alex'))
复制代码

#2、有参存储过程   #在mysql中参数必须指定类型,是用来接收值的还是返回值的
对于存储过程,可以接收参数,其参数有三类:
#in          仅用于传入参数用
#out        仅用于返回值用
#inout     既可以传入又可以当作返回值

    delimiter //
    create procedure p2(in n1 int,in n2 int,out res int) #当存储过程p1执行完了,就把res当做返回值返回了这就是out的作用,只有out的值才能被返回
    BEGIN
        select * from db7.teacher where tid > n1 and tid < n2;
        set res = 1;
    END //
    delimiter ;


    # MySQL中调用
    set @x=0 #初始值等于零
    call p2(2,4,@x);
    select @x;查看结果

    # Python中调用
    cursor.callproc('p2',(2,4,0))# @_p2_0=2,@_p2_1=4,@_p2_2=0
    cursor.execute('select @_p3_2')
    cursor.fetchone()
复制代码
mysql> delimiter //
mysql> create procedure p2(in n1 int, in n2 int, out res int)
    -> BEGIN
    -> select * from db7.teacher where tid > n1 and tid < n2;
    -> set res = 1;
    -> END //
Query OK, 0 rows affected (0.06 sec)

mysql> delimiter ;

mysql> set @x=0;
Query OK, 0 rows affected (0.00 sec)

mysql> call p2(2,4,@x);
+-----+-----------------+
| tid | tname           |
+-----+-----------------+
|   3 | 刘海燕老师      |
+-----+-----------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

mysql> select @x;
+------+
| @x   |
+------+
|    1 |
+------+
1 row in set (0.00 sec)
复制代码
复制代码
import pymysql

# 建立链接
conn=pymysql.connect(
    host='192.168.1.123',
    port=3306,
    user='root',
    password='123',
    db='db7',
    charset='utf8'
)

# 拿游标
cursor=conn.cursor()

#
cursor.execute('select @_p2_2')
print(cursor.fetchone())

# 关闭
cursor.close()
conn.close()

打印
(1, )
复制代码

应用程序与数据库结合使用
方式一: (很少用,部门之间沟通效率不高;优点很好解开了耦合,效率最高)
    Python:调用存储过程
    MySQL:编写存储过程

    
方式二:
    Python:编写纯生SQL  (可维护性好,都是开发人员写的,)
    MySQL:
    
方式三:
    Python:ORM->纯生SQL (开发效率高,可维护性高,用类,ORM框架)
    MySQL:

事务

同时成功同时失败;

 事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性。

复制代码
mysql> create table user(
    -> id int primary key auto_increment,
    -> name char(32),
    -> balance int
    -> );
Query OK, 0 rows affected (1.98 sec)

mysql>
mysql> insert into user(name,balance)
    -> values
    -> ('wsb',1000),
    -> ('egon',1000),
    -> ('ysb',1000);
Query OK, 3 rows affected (0.50 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> select * from user;
+----+------+---------+
| id | name | balance |
+----+------+---------+
|  1 | wsb  |    1000 |
|  2 | egon |    1000 |
|  3 | ysb  |    1000 |
+----+------+---------+
3 rows in set (0.00 sec)

#原子操作 mysql
> start transaction; Query OK, 0 rows affected (0.05 sec) mysql> update user set balance=900 where name='wsb'; #买支付100元 Query OK, 1 row affected (0.11 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> update user set balance=1010 where name='egon'; #中介拿走10元 Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> update user set balance=1090 where name='ysb'; #卖家拿到90元 Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from user; +----+------+---------+ | id | name | balance | +----+------+---------+ | 1 | wsb | 900 | | 2 | egon | 1010 | | 3 | ysb | 1090 | +----+------+---------+ 3 rows in set (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.16 sec) mysql> select * from user; +----+------+---------+ | id | name | balance | +----+------+---------+ | 1 | wsb | 900 | | 2 | egon | 1010 | | 3 | ysb | 1090 | +----+------+---------+ 3 rows in set (0.00 sec) mysql> rollback; #出现异常就回滚到初始状态 Query OK, 0 rows affected (0.00 sec) mysql> select * from user; +----+------+---------+ | id | name | balance | +----+------+---------+ | 1 | wsb | 900 | | 2 | egon | 1010 | | 3 | ysb | 1090 | +----+------+---------+ 3 rows in set (0.00 sec)
复制代码

函数与流程控制

函数

复制代码
一、数学函数
    ROUND(x,y)
        返回参数x的四舍五入的有y位小数的值

    RAND()
        返回0到1内的随机值,可以通过提供一个参数(种子)使RAND()随机数生成器生成一个指定的值。

二、聚合函数(常用于GROUP BY从句的SELECT查询中)
    AVG(col)返回指定列的平均值
    COUNT(col)返回指定列中非NULL值的个数
    MIN(col)返回指定列的最小值
    MAX(col)返回指定列的最大值
    SUM(col)返回指定列的所有值之和
    GROUP_CONCAT(col) 返回由属于一组的列值连接组合而成的结果    

三、字符串函数

    CHAR_LENGTH(str)
        返回值为字符串str 的长度,长度的单位为字符。一个多字节字符算作一个单字符。
    CONCAT(str1,str2,...)
        字符串拼接
        如有任何一个参数为NULL ,则返回值为 NULL。
    CONCAT_WS(separator,str1,str2,...)
        字符串拼接(自定义连接符)
        CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。

    CONV(N,from_base,to_base)
        进制转换
        例如:
            SELECT CONV('a',16,2); 表示将 a 由16进制转换为2进制字符串表示

    FORMAT(X,D)
        将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若  D 为 0, 则返回结果不带有小数点,或不含小数部分。
        例如:
            SELECT FORMAT(12332.1,4); 结果为: '12,332.1000'
    INSERT(str,pos,len,newstr)
        在str的指定位置插入字符串
            pos:要替换位置其实位置
            len:替换的长度
            newstr:新字符串
        特别的:
            如果pos超过原字符串长度,则返回原字符串
            如果len超过原字符串长度,则由新字符串完全替换
    INSTR(str,substr)
        返回字符串 str 中子字符串的第一个出现位置。

    LEFT(str,len)
        返回字符串str 从开始的len位置的子序列字符。

    LOWER(str)
        变小写

    UPPER(str)
        变大写

    REVERSE(str)
        返回字符串 str ,顺序和字符顺序相反。

    SUBSTRING(str,pos) , SUBSTRING(str FROM pos) SUBSTRING(str,pos,len) , SUBSTRING(str FROM pos FOR len)
        不带有len 参数的格式从字符串str返回一个子字符串,起始于位置 pos。带有len参数的格式从字符串str返回一个长度同len字符相同的子字符串,起始于位置 pos。 使用 FROM的格式为标准 SQL 语法。也可能对pos使用一个负值。假若这样,则子字符串的位置起始于字符串结尾的pos 字符,而不是字符串的开头位置。在以下格式的函数中可以对pos 使用一个负值。

        mysql> SELECT SUBSTRING('Quadratically',5);
            -> 'ratically'

        mysql> SELECT SUBSTRING('foobarbar' FROM 4);
            -> 'barbar'

        mysql> SELECT SUBSTRING('Quadratically',5,6);
            -> 'ratica'

        mysql> SELECT SUBSTRING('Sakila', -3);
            -> 'ila'

        mysql> SELECT SUBSTRING('Sakila', -5, 3);
            -> 'aki'

        mysql> SELECT SUBSTRING('Sakila' FROM -4 FOR 2);
            -> 'ki'

四、日期和时间函数
    CURDATE()或CURRENT_DATE() 返回当前的日期
    CURTIME()或CURRENT_TIME() 返回当前的时间
    DAYOFWEEK(date)   返回date所代表的一星期中的第几天(1~7)
    DAYOFMONTH(date)  返回date是一个月的第几天(1~31)
    DAYOFYEAR(date)   返回date是一年的第几天(1~366)
    DAYNAME(date)   返回date的星期名,如:SELECT DAYNAME(CURRENT_DATE);
    FROM_UNIXTIME(ts,fmt)  根据指定的fmt格式,格式化UNIX时间戳ts
    HOUR(time)   返回time的小时值(0~23)
    MINUTE(time)   返回time的分钟值(0~59)
    MONTH(date)   返回date的月份值(1~12)
    MONTHNAME(date)   返回date的月份名,如:SELECT MONTHNAME(CURRENT_DATE);
    NOW()    返回当前的日期和时间
    QUARTER(date)   返回date在一年中的季度(1~4),如SELECT QUARTER(CURRENT_DATE);
    WEEK(date)   返回日期date为一年中第几周(0~53)
    YEAR(date)   返回日期date的年份(1000~9999)

    重点:
    DATE_FORMAT(date,format) 根据format字符串格式化date值

       mysql> SELECT DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y');
        -> 'Sunday October 2009'
       mysql> SELECT DATE_FORMAT('2007-10-04 22:23:00', '%H:%i:%s');
        -> '22:23:00'
       mysql> SELECT DATE_FORMAT('1900-10-04 22:23:00',
        ->                 '%D %y %a %d %m %b %j');
        -> '4th 00 Thu 04 10 Oct 277'
       mysql> SELECT DATE_FORMAT('1997-10-04 22:23:00',
        ->                 '%H %k %I %r %T %S %w');
        -> '22 22 10 10:23:00 PM 22:23:00 00 6'
       mysql> SELECT DATE_FORMAT('1999-01-01', '%X %V');
        -> '1998 52'
       mysql> SELECT DATE_FORMAT('2006-06-00', '%d');
        -> '00'

五、加密函数
    MD5()    
        计算字符串str的MD5校验和
    PASSWORD(str)   
        返回字符串str的加密版本,这个加密过程是不可逆转的,和UNIX密码加密过程使用不同的算法。

六、控制流函数            
    CASE WHEN[test1] THEN [result1]...ELSE [default] END
        如果testN是真,则返回resultN,否则返回default
    CASE [test] WHEN[val1] THEN [result]...ELSE [default]END  
        如果test和valN相等,则返回resultN,否则返回default

    IF(test,t,f)   
        如果test是真,返回t;否则返回f

    IFNULL(arg1,arg2) 
        如果arg1不是空,返回arg1,否则返回arg2

    NULLIF(arg1,arg2) 
        如果arg1=arg2返回NULL;否则返回arg1     
复制代码

 

复制代码
mysql> CREATE TABLE blog (
    ->     id INT PRIMARY KEY auto_increment,
    ->     NAME CHAR (32),
    ->     sub_time datetime
    -> );
Query OK, 0 rows affected (0.78 sec)

mysql> INSERT INTO blog (NAME, sub_time)
    -> VALUES
    ->     ('第1篇','2015-03-01 11:31:21'),
    ->     ('第2篇','2015-03-11 16:31:21'),
    ->     ('第3篇','2016-07-01 10:21:31'),
    ->     ('第4篇','2016-07-22 09:23:21'),
    ->     ('第5篇','2016-07-23 10:11:11'),
    ->     ('第6篇','2016-07-25 11:21:31'),
    ->     ('第7篇','2017-03-01 15:33:21'),
    ->     ('第8篇','2017-03-01 17:32:21'),
    ->     ('第9篇','2017-03-01 18:31:21');
Query OK, 9 rows affected (0.14 sec)
Records: 9  Duplicates: 0  Warnings: 0

mysql> SELECT DATE_FORMAT(sub_time,'%Y-%m'),COUNT(1) FROM blog GROUP BY DATE_FORMAT(sub_time,'%Y-%m');
+-------------------------------+----------+
| DATE_FORMAT(sub_time,'%Y-%m') | COUNT(1) |
+-------------------------------+----------+
| 2015-03                       |        2 |
| 2016-07                       |        4 |
| 2017-03                       |        3 |
+-------------------------------+----------+
3 rows in set (0.22 sec)

mysql>
复制代码

流程控制

复制代码
delimiter //
CREATE PROCEDURE proc_if ()
BEGIN

    declare i int default 0;
    if i = 1 THEN
        SELECT 1;
    ELSEIF i = 2 THEN
        SELECT 2;
    ELSE
        SELECT 7;
    END IF;

END //
delimiter ;

if条件语句
复制代码

 

3、索引原理

索引在MySQL中也叫做“键”,是存储引擎用于快速找到记录的一种数据结构。

索引相当于字典的音序表,如果要查某个字,如果不使用音序表,则需要从几百页中逐页去查。

若索引太多,应用程序的性能可能会受到影响。而索引太少,对查询性能又会产生影响,要找到一个平衡点,这对应用程序的性能至关重要。

索引的目的在于提高查询效率,与我们查阅图书所用的目录是一个道理:先定位到章,然后定位到该章下的一个小节,然后找到页数。相似的例子还有:查字典,查火车车次,飞机航班等

本质都是通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是说,有了这种索引机制,我们可以总是用同一种查找方式来锁定数据。

数据库复杂的多,因为不仅面临着等值查询,还有范围查询(>、<、between、in)、模糊查询(like)、并集查询(or)等等。数据库应该选择怎么样的方式来应对所有的问题呢?我们回想字典的例子,能不能把数据分成段,然后分段查询呢?最简单的如果1000条数据,1到100分成第一段,101到200分成第二段,201到300分成第三段......这样查第250条数据,只要找第三段就可以了,一下子去除了90%的无效数据。但如果是1千万的记录呢,分成几段比较好?稍有算法基础的同学会想到搜索树,其平均复杂度是lgN,具有不错的查询性能。但这里我们忽略了一个关键的问题,复杂度模型是基于每次相同的操作成本来考虑的。而数据库实现比较复杂,一方面数据是保存在磁盘上的,另外一方面为了提高性能,每次又可以把部分数据读入内存来计算,因为我们知道访问磁盘的成本大概是访问内存的十万倍左右,所以简单的搜索树难以满足复杂的应用场景。

  当一次IO时,不光把当前磁盘地址的数据,而是把相邻的数据也都读取到内存缓冲区内,因为局部预读性原理告诉我们,当计算机访问一个地址的数据的时候,与其相邻的数据也会很快被访问到。每一次IO读取的数据我们称之为一页(page)。

  每次查找数据时把磁盘IO次数控制在一个很小的数量级,最好是常数数量级。那么我们就想到如果一个高度可控的多路搜索树是否能满足需求呢?就这样,b+树应运而生(B+树是通过二叉查找树,再由平衡二叉树,B树演化而来)。

 

b+树性质 1.索引字段要尽量的小;2.索引的最左匹配特性

这种数据结构减少I/O次数

真实数据只存在叶子节点的磁盘块的数据项;树杈节点的数据象就是为了建数据结构而虚拟出的;

I/O固定在固定范围,3次,它的高度决定的。

InnoDB存储引擎表示索引组织表,即表中数据按照主键顺序存放,建表的时候一定要建个主键,它会在你这个表里边找主键;

聚集索引与辅助索引

数据库中的B+树索引可以分为聚集索引(clustered index)和辅助索引(secondary index),

聚集索引与辅助索引相同的是:不管是聚集索引还是辅助索引,其内部都是B+树的形式,即高度是平衡的,叶子结点存放着所有的数据。

聚集索引与辅助索引不同的是:叶子结点存放的是否是一整行的信息

posted @ 2020-02-19 11:20  啊啊啊啊鹏  阅读(114)  评论(0编辑  收藏  举报
1 2