NoSQL 是 Not Only SQL 的缩写,意即"不仅仅是SQL"的意思,泛指非关系型的数据库。它不一定遵循传统数据库的一些基本要求,比如说遵循SQL标准、事务的ACDI属性、表结构等等。相比传统数据库,叫它分布式数据管理系统更贴切,数据存储更加灵活多样。
1、代表着不仅仅是SQL
2、没有声明性查询语言
3、没有预定义的模式
4、键 - 值对存储,列存储,文档存储,图形数据库
5、最终一致性,而非ACID属性
6、非结构化和不可预知的数据
7、高性能,高可用性和可伸缩性
Redis是一款开源的、高性能的键-值存储(key-value store)它常被称作是一款数据结构服务器(data structure server)。Redis的键值可以包括字符串(strings)类型,同时它还包括**哈希(hashes)、列表(lists)、集合(sets)和 有序集合(sorted sets)**等数据类型。 对于这些数据类型,你可以执行原子操作。例如:对字符串进行附加操作(append);递增哈希中的值;向列表中增加元素;计算集合的交集、并集与差集等。
为了获得优异的性能,Redis采用了内存中(in-memory)数据集(dataset)的方式。同时,Redis支持数据的持久化,你可以每隔一段时间将数据集转存到磁盘上(snapshot),或者在日志尾部追加每一条操作命令(append only file,aof)。
Redis同样支持主从复制(master-slave replication),并且具有非常快速的非阻塞首次同步( non-blocking first synchronization)、网络断开自动重连等功能。同时Redis还具有其它一些特性,其中包括简单的事物支持、发布订阅 ( pub/sub)、管道(pipeline)和虚拟内存(vm)等 。
Redis具有丰富的客户端,支持现阶段流行的大多数编程语言。php常用的是phpredis( http://redis.io/clients )
是redis最基本的数据类型,以键值对的形式存储数据(value-key)最大可以存储512MB。
实例:
是一个键值(key=>value)对集合, 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象
。最多可以存储232-1(40多亿)
实例
-redis> HMSET myhash field1 “Hello” field2 “World”
-“OK”
-redis> HGET myhash field1
-“Hello”
-redis> HGET myhash field2
-“World”
每一个子元素都是string类型的双向链表,最大长度是2^32-1。既可以做栈也可以做队列。可以从头(左)添加也可以从尾(右)添加。
实例:
redis 127.0.0.1:6379> lpush runoob redis
(integer) 1
redis 127.0.0.1:6379> lpush runoob mongodb
(integer) 2
redis 127.0.0.1:6379> lpush runoob rabitmq
(integer) 3
redis 127.0.0.1:6379> lrange runoob 0 10
什么是数据库?数据库的种类有哪些?
数据库:
高效的存储和处理数据的介质(主要分为磁盘和内存两种)
关系型数据库:
大型:Oracle、DB2 等;
中型:SQL Server、MySQL、PostgreSQL等;
小型:Access 等。
非关系型数据库:
Memcached、MongoDB、Redis、Elasticserach等。
关系数据库管理系统,开放源码软件,目前属于 Oracle 旗下产品。C\S结构的软件
体系结构
一条select的生存周期
结构化查询语言
数据查询语言DQL:用于检索数据库中数据记录等,如SELECT
select name,age from students;
数据操纵语言DML:用于改变数据库中的数据记录等,如INSERT、UPDATE 、DELETE
insert into students (name,age,sex,classid) values (’小明’,20,’男’,1);
数据定义语言DDL:用于建立,修改,删除数据库中的各种对象如表、视图、索引等,如CREATE、 TABLE/VIEW/INDEX/SYN/CLUSTER、ALTER、DROP
alter table student add index idx_cid (classid);
数据控制语言DCL:用来授予或回收访问数据库的某种特权,并控制数据库操纵事务发生的时间及效果,对数据库实行监视等,如GRANT、REVOKE、COMMIT
grant select on . to readonly@’%’;
连接使用
前提:MySQL服务、客户端工具、合法的账号
MySQL系统库
information_schema、performance_schema、sys、mysql
show databases;
create database test;
use test;
create table test (
id int(10) not null auto_increment,
name varchar(20) not null default ‘’ comment ‘名称’,
note varchar(10) not null default ‘’ comment ‘备注’,
primary key(id),
key idx_name(name)
)engine=innodb auto_increment=1 default charset utf8 comment ‘测试表’;
inser into test (name,note) values (‘Tom’,‘student’),(‘Jim’,‘student’);
select name,note from test;
JAVA
jdbc.driver=com.mysql.jdbc.Driver
jdbc.user=root
jdbc.password=root
jdbc.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bookstore
Python
mysql+pymysql://root:[email protected]:3306/flask?charset=utf8
注:个人账号和应用账号及连接数据库使用域名
库表操作
创建数据库
CREATE {DATABASE | SCHEMA} [IF NOT EXISTS] db_name DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
查看建库语句
SHOW CREATE DATABASE db_name;
显示所有的数据库
SHOW DATABASES;
删除数据库
DROP DATABASE db_name;
新建规范
CREATE TABLE tb_student (
id BIGINT UNSIGNED NOT NULL auto_increment,
– 必须要有主键,必须有注释
snum INT NOT NULL DEFAULT 0 COMMENT ‘学号’,
– 不允许存在NULL值
NAME VARCHAR (10) NOT NULL DEFAULT ‘’ COMMENT ‘学生姓名’,
– 给默认值
age INT NOT NULL DEFAULT 0 COMMENT ‘年龄’,
sex VARCHAR (2) NOT NULL DEFAULT ‘’ COMMENT ‘性别’,
class_id INT NOT NULL DEFAULT 0 COMMENT ‘班级id’,
PRIMARY KEY (id),
KEY idx_sname (class_id) – 一切外键关系必须在应用层解决
) ENGINE = INNODB DEFAULT CHARSET utf8 COMMENT ‘学生表’;
更改表
ALTER TABLE tb_name [ADD | DROP | MODIFY …] COLUMN …
ALTER TABLE test ADD date BIGINT NOT NULL DEFAULT 0 COMMENT ‘时间’,
MODIFY NAME NAME VARCHAR (30) NOT NULL DEFAULT ‘’ COMMENT ‘名称’;
– 同一个表的多个涉及到字段的操作,放到一个SQL里面完成
增删改
INSERT
第一种
INSERT INTO tb_name [ (col1_name,col2_name ,…) ]
VALUES(col1_value,col2_value ,…) [, (col1_value,col2_value ,…)…]
如:
INSERT INTO test_db.test_tb (stu_num, NAME, age, sex)
VALUES
(1123, ‘Tom’, 10, ‘m’),
(1124, ‘Jary’, 11, ‘f’);
1)使用WHERE条件能确定到具体的某条记录上的更新或删除语句,不能有歧义导致误删数据。避免使用分组及排序语句。
2)TRUNCATE和DELETE只删除数据不删除表的结构(定义),但是DELETE可以回滚,会出发DELETE触发器,而TRUNCATE则不可以回滚,且不会触发DELETE触发器。DROP删除数据及结构,不能回滚。
3)速度和效率上一般来说: DROP> TRUNCATE> DELETE,但是要慎用前两者。
简单查询
无限定条件查询:
查询单个列:SELECT name FROM test_db.test_tb;
查询多个列:SELECT name, age,sex FROM test_db.test_tb;
查询所有列:SELECT * FROM test_db.test_tb;(实际生产中不要使用select * 通配查询)
WHERE条件:
查找年龄大于15周岁的多个列信息:
SELECT NAME,age,sex FROM test_db.test_tb WHERE age > 15;
查找年龄大于15周岁并且性别为男的多个列信息
SELECT NAME, age, sex FROM test_db.test_tb WHERE age > 15 AND sex = ‘男’;
查找主键ID为11,12,13,14,15的信息:
SELECT NAME, age, sex FROM test_db.test_tb WHERE id IN (11,12,13, 14,15);
查找姓李的人的信息
SELECT name, age,sex FROM test_db.test_tb WHERE name LIKE ‘李%’;
查找年龄在15到30岁之间,并且这些人的主键id要在100以内的人的姓名:
SELECT NAME, age, sex FROM test_db.test_tb WHERE NAME LIKE ‘李%’;
ORDER BY 排序:
根据年龄排序:
SELECT name, age,sex FROM test_db.test_tb where age>15 order by age asc;
根据两个条件进行倒序排序:
SELECT NAME, age, sex
FROM test_db.test_tb
WHERE NAME LIKE ‘王%’
ORDER BY createtime DESC, age DESC;
GROUP BY 分组:
每个班级的人数汇总:
select count(1),class_id from student group by class_id;
班级人数男女总数:
select count(1),sex from student group by sex;
查询中使用函数:
查询test_db.test_tb表的总行数
SELECT COUNT(*) FROM test_db.test_tb ;
查询最小年龄是多少:
SELECT MIN(age) FROM test_db.test_tb ;
按年龄分组,查找每个年龄各有多少人数,并且其总人数大于10人:
SELECT COUNT(*) stu_sum,age FROM test_db.test_tb GROUP BY age HAVING stu_sum>10;
常用的函数
COUNT()、SUM()、MAX()、MIN()、FROM_UNIXTIME()、UNIX_TIMESTAMP()、NOW()、SUBSTRING_INDEX()、IFNULL()、CASE…WHEN…THEN…ELSE…END
子查询
查询所有年龄为最小年龄的人信息:
SELECT NAME, age, sex
FROM test_db.test_tb
WHERE age = (
SELECT MIN(age)
FROM test_db.test_tb );
为什么要建立和使用索引?
索引是独立数据之外而存在的一种存储介质,并且在mysql启动的时候会默认加载到缓冲池中(内存)。相对于从磁盘中物理读取数据内容,从内存中读取索引数据的速度更快(10倍+)。
索引命名
使用小写字母,过长的字段名可以采⽤缩写形式
普通索引按“idx_字段名称[_字段名称]”格式(idx_contractNo)
唯一索引按“uniq_字段名称[_字段名称]”格式(uniq_phone)
建立条件
目标的数据表有查询需求。(对无查询需求的日志表可以不建立索引提高写入速度)
目标数据表未来数据量大于1000条。
索引选择性
是指某个字段的不重复值的数量占总行数的比例,这个比例越接近1,则选择性越高,如果有该字段上的查询需求,更适合建立索引。
select count(distinct name)/count() from employee;
select count(distinct left(name,10))/count() from employee;
多列的索引选择性
查询:select name,mobile,status from employee where name=‘张三’ and status=0;
这个时候怎么建立索引?
多列索引的索引hit原则?
现在有一如下多列索引:
idx_name_mobile_ctime(name,mobile,create_time)
1
可以使用到该索引的查询:
select name,mobile,status from employee where name=‘张三’ and mobile=‘139*****’ and create_time > 1494310361 and create_time < 1494312361;
select name,mobile,status from employee where name=‘张三’ and mobile=‘139*****’;
select name,mobile,status from employee where name=‘张三’;
1
2
3
无法使用该索引的查询:
select name,mobile,status from employee where mobile=‘139*****’ and create_time > 1494310361 and create_time < 1494312361;
select name,mobile,status from employee where mobile=‘139*****’;
select name,mobile,status from employee where create_time > 1494310361 and create_time < 1494312361;
1
2
3
如何正确的使用多列索引呢?
需要考虑每层级的索引选择性:
select name,mobile,status from employee where name=‘张三’ and mobile=‘139****’ and create_time > 1494310361 and create_time < 1494312361;
1
分别查询一下3中索引选择性:
select count(distinct name)/count(*) from employee;
select count(distinct name,mobile)/count(*) from employee;
select count(distinct name,mobile,create_time)/count(*) from employee;
1
2
3
如果结果是:0.91 0.94 0.99 可以仅对name列建立单列索引即可。
如果结果是:0.61 0.94 0.99 可以对name,mobile列建立复合索引(即多列索引)即可。
如果除了上述包含3个条件的查询之外还有针对mobile列的单独高频率查询,建议另外建立一列为mobile的单列索引:idx_mobile。
前缀索引的适用场景
对某些长度较大的字段有需求建立索引的时候建立。 varchar(100)
语法格式
alter table employee add key idx_title(title(10));
如何选择合适的长度?
依然使用索引选择性进行长度圈定。
select count(distinct left(title,50))/count(distinct title) from employee; 0.999
select count(distinct left(title,8))/count(distinct title) from employee; 0.9574
select count(distinct left(title,6))/count(distinct title) from employee; 0.5286
根据上述查询结果,使用idx_title(title(8))
inner join、left join的关联字段一定要建立索引
select name,mobile from employee a inner join department b on a.department_id=b.id;
– 这里employee的department_id的是否有索引直接影响到查询效率
不要使用in ()子查询的方式,很多情况下无法使用索引
select name,mobile from employee where department_id in (select id from department);
查询的字段如果是varchar类型一定要使用单引号括住常量值
先假设mobile字段是varchar字段(实际使用过程中纯数字的字段尽量使用int、bigint、decimal等数字类型)
select name,mobile from employee where mobile = 13934563352; – 无法使用索引
select name,mobile from employee where mobile = ‘13934563352’; – 可以使用索引
练习
现在有一个需求,需要创建一张超简单的学生表(tb_student),其中学生的属性有学号snum、姓名name、年龄age、性别sex和班级class_id,问这张表的创建语句如何写(MySQL语法)?
CREATE TABLE tb_student (
id BIGINT UNSIGNED NOT NULL auto_increment,
snum INT NOT NULL DEFAULT 0 COMMENT ‘学号’,
NAME VARCHAR (10) NOT NULL DEFAULT ‘’ COMMENT ‘学生姓名’,
age INT NOT NULL DEFAULT 0 COMMENT ‘年龄’,
sex VARCHAR (2) NOT NULL DEFAULT ‘’ COMMENT ‘性别’,
class_id INT NOT NULL DEFAULT 0 COMMENT ‘班级id’,
PRIMARY KEY (id),
KEY idx_sname (class_id)
) ENGINE = INNODB DEFAULT CHARSET utf8 COMMENT ‘学生表’;
现在有两个学生,分别是小明和小红,信息分别为:
小明,学号201901211314,21岁,男,id为1013的班级;
小红,学号201901221314,20岁,女,id为1016的班级;
请问,如何将这两条信息写入到刚刚新建的表里面?
INSERT INTO tb_student (snum, NAME, age, sex, class_id)
VALUES(201901211314, ‘小明’, 21, ‘男’, 1013),
(201901221314, ‘小红’, 20, ‘女’, 1014);
假如1013班目前有36个人,请问,如何从这个表中使用sql得出1013班的平均年龄?并判断1013班和1014班哪个班平均年龄小,并按照从大到小的顺序排列?
SELECT class_id, avg(age) avg_age
FROM tb_student
GROUP BY class_id
ORDER BY avg_age DESC;