数据库

数据库

基础 #

数据库类型
    关系型数据库
    模糊型数据库
        # 存放模糊数据,提供函数
        如模糊数,包括模糊区间数,模糊中心数,模糊集合数
        隶属函数
    统计数据库
        # 管理统计数据
        这类数据库包含有大量的数据记录,但其目的是向用户提供各种统计汇总信息,而不是提供单个记录的信息。
    网状数据库(层次数据库)
        # 处理以记录类型为结点的网状数据模型
        处理方法是将网状结构分解成若干棵二级树结构,称为系。
    演绎数据库
        # 指具有演绎推理能力
        实现
            数据库管理系统
            规则管理系统
        外延数据库
            将推理用的事实数据存放在数据库中
        内涵数据库
            用逻辑规则定义要导出的事实
        主要研究内容: 如何有效地计算逻辑规则推理。
            递归查询的优化
            规则的一致性维护

其它数据存储方式
    文件系统
        版本控制
    保存持久状态
        CQRS(command query responsibility segregation)
            查询(query)
            命令(command)
            领域模型(domain model)
            领域事件(domain event)
    对象数据库
趋势
    分布式new sql  # tidb
    Polyglot persistence (混合持久化)
        # 将对不同数据库的操作封装成服务

事务隔离级别
    读未提交(Read Uncommitted)  # 读其它事务未提交的数据
        现象
            不允许更新丢失
            允许脏读(dirty read)               # 事务中读到不存在数据, 是其它事务修改中的数据
        原理
            可同时读
            不同时写,多事务写
        实现
            排他写锁
    读提交(Read Committed)                    # 读其它事务提交的数据
        现象
            不允许脏读
            允许不可重复读(nonRepeatable read)   # 事务中前后查询不一致
        原理
            可同时读
            单事务写
        实现
            瞬间共享读锁
            排他写锁
    可重复读(Repeatable Read)                  # 读到的数据加锁,解决不可重复读问题
        现象
            不允许脏读
            不允许不可重复读
            允许幻读(phantom read)               # 事务中存在未生效行,是其它事务的插入或删除
        原理
            读到的数据(加锁)不写
            单事务写
        实现      # 读涉及范围加锁
            共享读锁
            排他写锁
    序列化(Serializable)       # 或叫串行化
        原理
            事务序列化执行
        实现
            读锁写锁互斥
事务特点(ACID)
    原子性(atomicity)          # 什么都做或都不做
    一致性(correspondence)     # 事务前后数据库状态一致, 事务中断时也不会有暂时状态
    隔离性(isolation)          # 事务间不干扰
    持久性(durability)         # 提交结果是永久的
索引存储
    B+ tree
    LSM(log-structured merge) tree
    fractal tree
OLTP和OLAP
    CAP(一致性、可用性、分区容错性)中, OLTP要求ca或cp, OLAP要求ap
    OLTP要求写优化, OLAP要求查优化
    OLTP要求优化latency, OLAP要求优化throughput
    OLTP基于row, OLAP基于column
    OLTP看中IOPS, OLAP看中data-size传输
分布式数据库
    面临问题
        ACID
        CAP
        scale out
        self-healing
        运维友好
        sql
        事务
        性能
        api用明文或二进制
        升级方案
        硬件,网络,网络模型,存储模型,语言
        分布式协议,压缩方案,ha,api,运维方案,存储计算分离,缓存方案

rds #

# relational database service
缺点
    阻抗失谐    # 和内存中的模型存在差异
安全
    sql注入   # 应该写符号编译sql
范式
    # Normal Form 用于避免冗余数据
    第一范式(1NF)
        列不可再细分列(原子性)
    第二范式(2NF)
        必须有主键,允许联合主键
        其它列依赖完整主键(不能只依赖一部分)
    第三范式(3NF)
        其它列直接依赖主键(非传递依赖,如A依赖B, B依赖主键)
实例
    postgres
    sqlserver
    mysql
    mariadb
    percona
        # mysql分支, Oracle发布的最接近官方mysql的发行版
    drizzle
        # mysql分支
    oracle
    db2
    oceandb
    h2database
        # java编写,可嵌入java使用
    tidb

sqlite #

命令
    sqlite3 数据库文件
语法
    .table              # 查看所有表
    .schema             # 查看建表语句

sql #

语法
    注释
        --      # 单行注释
        /**/    # 多行注释
    单引号
        字符串大小写敏感
    双引号
        转日期时, 双引号直接显示。to_char(sysdate,'yyyy "年" mm "月" dd "日" day')
    表别名不加as关键字, 有别名后原名无效
    oracle
        ||      # 管道符号
            select ename || '的薪水是' || sal from emp;
定义(DDL, data definition language)
    create database db1             # create or replace
        default character set utf8          # 默认编码
        collate utf8_general_ci;    # 校对规则(排序), ci(case insensitive)大小写不敏感, cs(case sensitive)大小写敏感
    create table `tb1`(           # create or replace
        `id` int unsigned unique not null auto_increment,
            # `id` int unsigned not null primary key,
        `id2` int unsigned,
        `name` varchar(20),
        `age` int unsigned,
        `birthday` date,
        primary key(`id`),          # 主键
        key idx_tb1_name (`name`),   # 索引
        foreign key(`id2`) references `tb2`(id) on delete cascade on update cascade     # 外键、级联删除、级联更新, 不要用
        )character set utf8 collate utf8_general_ci
        engine=innodb default charset=utf8;
    create table person like student;           # 复制表结构
    create table emp1 as select * from emp;     # 复制内容
    create view tb1_v (a,b) as select a, b from tb1 #  create or replace
    create synonym tb2 for tb1;     # 同义词

    drop database db1;
    drop table tb1
        purge;              # 加purge不放入回收站
    drop synonym tb1;

    truncate table tbq;


    alter database db1
        character set gbk
        collate gbk_chinese_ci;        # 更改数据库的编码
    alter table tb1
        add column sex char(1);
    alter table tb1
        add constraint pr_id primary key (id);   # 添加主键
    alter table tb1
        add constraint fk_id2 foreign key (st_id) references tb2(id);  # 添加外键
    alter table tb1
        rename to tb2;
    alter table tb1
        change sex gender char(1);      # 只能改名,但类型必须写
    alter table tb1
        modify birthday varchar(20);    # 只能改类型
    alter table tb1
        convert to character set utf8 collate utf8_general_ci;  # 转换表编码
    alter table tb1
        drop column name;
    alter table field1
        auto_increment = 5;             # 更改自增长初始值


    rename table tb1 to tb2;

    desc tb1;


    mysql
        use db1

        source a.sql            # 批执行

        show status [from schema_name];         # 服务器状态
        show databases;
        show create database db1;
        show tables;
        show create table tb1;
        show processlist                        # 查看当前连接
        show VARIABLES LIKE "general_log%"      # 查看变量 
            "version"                           # 显示版本
            "autocommit"                        # 事务开启状态 0 off 1 on, set autocommit=off 或 0
        show character set                      # 显示所有字符集



        select @@sql_mode                       # 查看变量
        select @@tx_isolation                   # 查看事务隔离级别
        select
        select VERSION()                        # 显示版本

        set sql_mode = ''                       # sql_mode定义支持的sql语法,数据校验。
        set names 'gbk';                        # 设置终端编码, 等价character_set_client=gbk 与 character_set_results=gbk
        set global general_log = 'ON'           # 设置记录所有sql

    oracle
        create table tb1 (
            sex char(1) check(sex in (0, 1))        # check约束
        show user                   # 显示用户名
        show recyclebin             # 回收站
        purge recyclebin            # 闪回文件
        oracle表创建时自动添加伪列
            rowid       # 唯一,指向当前记录
            rownum      # 唯一,字段列名, 从1开始,永远连续。
                # 支持比较符号 <, <=(可以比较=1)。取别名后可以比较 >, =


操作(DML, data manipulation language)
    # 和DQL, data query language, select、from、where
    insert into tb1
        values (3, 'a', null);
    insert into tb1
        select * from tb2;
    insert into tb1(name)
        values ('a'),('b');
    insert into tb1(a, b)
        select c, d from tb2

    update tb1
        set name='a'

    delete from tb1


    select * from outrun.employee;      # 限定数据库名
    select field1 as f1 from tb1 as t1
    select a, b into tb2 from tb1;
    select distinct (a+b) as c from tb1
        # select distinct sum(price) as s
    子查询
        # 要求数量和类型匹配
        # 不能利用索引(join可以), 不形成笛卡尔积

        where a < (select max(a) from tb2)
            # 单行符号 =、<、>
        where a in ()
            # 多行符号 in、any、all
            where a < any ()    # 小于一个就true
            where a < all ()    # 小于所有才true



    where a=1 and b=2                   # where后不能出现列的别名,可以出现表的别名
        a=1 or b=2
            # <>表示!=
            # =可设置日期
        a in (1,2)
            # a not in (1,2)
        a between 1 and 2
            # a not between 1 and 2
        a like 'a%'
            # 不能用*
            # % 匹配任意个字符
            # _ 匹配一个字符
            # \ 转义 _ 或 %
        a regexp '^.*d.*$'
            # 匹配正则
        a is null
    order by    # null看作最大值
        a asc   # 升序
        a desc  # 降序
    group by
        select a, count(b), avg(c) from tb1     # group by的select元素都是聚合函数
            where b > 0
            group by a
            having count(b) > 2                 # having使用聚合函数条件
        select a from tb1                       # 子查询
            where b in (select b from tb2 where c='c')
            group by a
            having count(distinct b) = (select count(*) from tb2 where c='c')


    select执行过程
        # 每步都产生虚拟表
        from 组装数据
            join
            on
        where 筛选
        group by 划分
        # with,  with是sql server的语法
        计算聚合函数
        having 筛选
        计算表达式
        select 字段
            distinct
        order by 排序
        top

    oracle
        insert into tb1 values(&id, '&s')                   # &是占位符,字符型数据加''
        alter table tb1 rename column field1 to field2

    常用
        分页
            select * from tb1 limit 0,1         # mysql, 从0开始,查找1条


            select * from                       # oracle
                (select rownum r, a from tb1 where rownum<=20)
            where r > 10

            select * from                       # oracle,  效率低
                (select  rownum rn, a from tb1)
            where rn between 21 and 40


            select rownum,emp.* from emp        # oracle, 效率低
                where rownum <=4
            minus
            select rownum,emp.* from emp
                where rownum <=2;

控制(DCL data control language)

    grant all privileges on db1.tb1         # 授权
        # grant insert,delete,update,select,create on db1.tb1
        to 'user1'@'host1'          # localhost本地 , %代表远程
        identified by 'pwd1'
        with grant option;          # 有授权权限
    grant select any table      # oracle
        to user1
    revoke select any table     # oracle
        from user1

    revoke privilege ON db1.tb1 from 'user1'@'host1';       # 撤销权限
    flush privileges;        # 提交授权修改, oracle不用flush直接生效


    oracle
        alter user user1 account unlock             # 解锁用户
        alter user user1 identified by user1        # 改密码
        conn / as sysdba                            # 换角色

事务
    start transaction;
    savepoint a;
    rollback to [savepoint] a;
    rollback;
    commit;

聚合函数
    avg()
    count()
    max()
    min()
    sum()


连接(join)
    内连接(inner)
        # 带条件的交叉连接
        # 只查出符合条件的记录
        select * from tb1 a         # 显示
            inner join tb2 b
            on a.c_id=b.c_id
        select * from tb1 a, tb2 b  # 隐示
            where a.c_id=b.c_id
        自连接     # 表中有层次关系。自连接无中间表, 效率快
            select a.c, b.d from course as a, course as b
                where a.c=b.d
    外连接(outer)
        # 以一表为基准,查另一表
        # 可查出不符合条件的记录(另一表无对应值,标记成null)
        左外连接
            # 以左为基准
            select * from tb1 as a
                left [outer] join tb2 as b
                on a.c_id=b.c_id

            select a.c_id       # oracle
            from tb1 a, tb2 b
            where a.c_id = b.c_id(+)
        右外连接
                right [outer] join
        全外连接
            # full [outer] join, 只oracle支持
            # 先左连接再右连接,取的是交集
            select * from a
                full join b
                on a.c_id=b.c_id
    交叉连接(cross)     # 笛卡尔积
        # 有where条件时,会先生成where查出的两个表
        select * from tb1 a
            [cross] join tb2 b
            where a.c_id = b.c_id;
    自然连接(natural)
        # 自动检查相同名称的列,类型会隐式转换,不能指定显示列(或用*)、不能用on语句
        # 每种连接名称前加natural都是自然连接
        select * from tb1 a
            natural innter join tb2 b
集合
    # 数量,类型匹配
    # 前语句别名可用,后语句别名不可用
    select a, b from tb1
        union [all] select a, b from tb2    # 并集, all 允许重复
            # intersect 交集
            # minus 差集

约束(constraint)
    not null
    unique
    primary key
        primary key unique, not null auto_increment
        primary key(col1, col2)     # 联合主键
    foreign key
        constraint fk_id2
            foreign key(id2) references tb2(id)
                # 被引用的列要建索引
                # 被引用的记录不可删除
                # 被引用的值要级联修改
            on update cascade
            on delete cascade
                # 级联约束
    检查约束    # oracle支持

存储过程 #

优势
    高效, 首次运行进行预编译
    模块化
    更快执行,大量sql时,比sql快
    减少网络流量
    安全机制
        针对过程授权
        调用时看不到语句信息和数据
        避免sql注入     # 参数视为文字
        可对过程加密
劣势
    不可移植
    需要专人维护
    逻辑变更时修改不灵活

触发器 #

用途
    表级联更改
    实现比check约束复杂的逻辑
    强制执行业务规则
    评估修改后表状态,执行操作
基础
    同一表不能建立2个相同类型触发器

视图 #

特点
    优点
        简化查询
        提供独立访问
        限制访问
    查看时,生成sql查看, 有即时性
    更新视图表级联
        不能更新的视图包含元素
            组函数
            distinct
            group by
            rownum
    grant可授权
    不能与表名重名
    mysql保存在information_schema.views中
    删除不放回收站

    CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]       # TEMPTABLE是临时表,不能更新
        VIEW view_name [(column_list)]
        AS select_statement
        [WITH [CASCADED | LOCAL] CHECK OPTION]                      # 通过该视图更改的数据,可再通过该视图查看到(满足视图的限制)
    o->
    CREATE VIEW test.v AS SELECT * FROM t;
    o->
    CREATE VIEW v AS SELECT qty, price, qty*price AS value FROM t;                # 可以计算
    o->
    CREATE VIEW v AS SELECT CHARSET(CHAR(65)), COLLATION(CHAR(65));                # 可以联合
    o->
    CREATE ALGORITHM = MERGE VIEW v_merge (vc1, vc2)
        AS SELECT c1, c2 FROM t1 WHERE c3 > 100

        查询解释
            SELECT * FROM v_merge WHERE vc1 < 100; 会执行
            SELECT c1, c2 FROM t WHERE (c3 > 100) AND (c1 < 100);


    ALTER [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}]
        VIEW view_name [(column_list)]
        AS select_statement
        [WITH [CASCADED | LOCAL] CHECK OPTION]              # CASCADED 忽略主外键关系

    DROP VIEW [IF EXISTS]
        view_name [, view_name] ...
        [RESTRICT | CASCADE]

    SHOW CREATE VIEW view_name

索引 #

特点
    第一次查询时创建
    加快查询的速度,表删除时索引自动删除
    primary key 与 unique 自动建立
命中
    where 中添加对应索引的条件, 只能从前向后命中
是否使用
    使用
        分布广
        经常在where中出现
        表经常访问
    不使用
        表小
        不经常出现的列
        经常更新的字段
类型
    index
    unique
    primary key

CREATE INDEX index_name ON table_name (column_list)         # 创建索引,primary key已有索引
CREATE UNIQUE INDEX index_name ON table_name (column_list)

ALTER TABLE table_name ADD INDEX index_name (column_list) # 创建索引,列名逗号分隔。index_name缺省时,根据第一个索引列取名
ALTER TABLE table_name ADD UNIQUE (column_list)
ALTER TABLE table_name ADD PRIMARY KEY (column_list)

DROP INDEX index_name ON talbe_name
ALTER TABLE table_name DROP INDEX index_name        # 等价于前一个
ALTER TABLE table_name DROP PRIMARY KEY

show index from tb1;
show keys from tb1;
    Table         # 表的名称。
    Non_unique    # 如果索引不能包括重复词,则为0。如果可以,则为1。
    Key_name      # 索引的名称。
    Seq_in_index  # 索引中的列序列号,从1开始。
    Column_name   # 列名称。
    Collation     # 列以什么方式存储在索引中。在MySQL中,有值‘A’(升序)或NULL(无分类)。
    Cardinality   # 索引中唯一值的数目的估计值。通过运行ANALYZE TABLE或myisamchk -a可以更新。基数根据被存储为整数的统计数据来计数,所以即使对于小型表,该值也没有必要是精确的。基数越大,当进行联合时,MySQL使用该索引的机会就越大。
    Sub_part      # 如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL。
    Packed        # 指示关键字如何被压缩。如果没有被压缩,则为NULL。
    Null          # 如果列含有NULL,则含有YES。如果没有,则该列含有NO。
    Index_type    # 用过的索引方法(BTREE, FULLTEXT, HASH, RTREE)。
    Comment       # 更多评注。

序列 #

# 共享对象唯一的数值,不一定连续
create sequence tb1_seq
    INCREMENT BY 10              # 步长是10
    START WITH 120               # 从120开始
    MAXVALUE 9999                # 最大到9999
    NOCACHE                      # 不缓存序列的值(缓存是先创建很多再取出,不缓存则是什么时候取,什么时候创建)
    NOCYCLE;                     # 到最大值的时候是否循环

select seq.nextval from dual                # nextval下一个序列 currval当前序列  第一次使用必须是nextval
insert into emp(id) vallues(seq.nextval);   # 使用
alter sequence tb1_seq increment by 10;
    start with 100;                         # 错误 ,不能变更启动序列,只能在创建序列时指定
drop sequence seq

性能优化 #

设计
    库
        分库
            拆微服务
            主从      # master不拆,slave树形
            索引与数据分库
    表
        不要代价高的关系(外键、级联)
        字段可冗余,为了提高性能,但要考虑同步。不能是频繁修改的字段,不是varchar和text
        单表行数超过500万或意表容量超过2GB,才分库分表
        分表  # 垂直分字段,水平分记录
            表名加hash到多表
            partitioning key字段分表    # proxy网关分流
                时间
                地点
            建lookup table查找对应表
            冷热分离
        用表变量代替临时表
        表变量数据大时,只有主键索引
        大量重复引用大型表或常用表数据时,可创建临时表。一次性事件,最好导出表
        临时表时数据大时, 用select into代替create table, 避免log过多
        临时表最后要先truncate, 再drop, 避免表较长时间锁定
    类型
        尽量not null
        数字类型尽量用
        char存几乎定长字符串类型
        varchar变长字符串,不预先分配空间,长度不要超过5000
        text存大于5000,独立出表用主键对应,避免影响其它字段索引效率
        bool用unsigned tinyint
        小数类型用decimal,不用float double
            # float和double存储的时候,存在精度损失的问题
            # 长度超过decimal范围,拆成整数和小数分开存
        合适的字符长度,不但节约表空间,节约索引存储,更提升检索速度
            unsigned tinyint    0到255
            unsigned smallint    0到65535
            unsigned int    0到42.9亿
            unsigned bigint    0到10的19次方
    索引
        有唯一特性,都建唯一索引
            # insert速度损耗可以忽略,但明显提高查找速度
            # 不建唯一索引,总会有脏数据产生
        where与order by涉及的列建索引
        建组合索引时,区分度最高的在左边
            where a=? and b=? ,a列几乎接近唯一值,只需要建idx_a索引
            非等号和等号混合时,等号是最左边,如where a>? and b=?, 那么b在索引最前列
        字段值大量重复时,索引作用不大
        索引降低insert与update效率
        索引数据列少更新           # 数据列为表存储方式,更新会调整整表存储
        varchar建索引,要指定索引长度
            一般字符串数据,长度为20的索引,区分度高达90%以上
            count(distinct left(列名,索引长度)) / count(*)来计算
语句
    where放弃索引,全盘扫描
        比较符
            in      # in元素尽量控制在1000内
            not in
            # exists代替in
                select num from a where num in(selct num from b)    改为
                select num from a where exists(select 1 from b where num=a.num)
            is null
            is not null
            <>
            or
            like '%a'模糊开头

        where对字段用表达式或运行函数
            where num/2=100 改为
            where num = 100*2

            where year(admin_time)>2014 改为
            where admin_time>'2014-01-01'
        where使用参数       # 因为运行时解析局部变量,访问计划在编译时进行
            select id from t where num=@num 改为
            select id from t with(index(索引名)) where num=@num    # 强制使用索引
    select
        不要写无意义查询
            select a into #t from t where 1=1 改为
            create table #t
        不要select *             # 增加查询分析器解析成本,增减字段容易与resultMap不一致
        不select for update      # 长期锁定行(游标默认都用)
            不要用游标
    函数
        使用count(*)统计行数
            用count(distinct col1, col2)来计算不重复
        sum(col)会返回null,如下解决
            SELECT IF(ISNULL(SUM(g)), 0, SUM(g)) FROM table1
        使用ISNULL()来判断NULL
            # NULL与任何值比较都为NULL
业务
    sql优化至少到range级别
        # explain结果type=
        # all 全表扫描
        # index 扫描整个索引表,几乎相当于全表扫描
        # range 用索引选择范围
        # ref 非唯一索引扫描
        # eq_ref 唯一索引扫描
        # consts 索引一下就找到,单表中最多有一个匹配行(主键或唯一索引), 在优化阶段即可读取到数据
        # system 表只有一行
    库
        不在数据库写逻辑           # 不使用存储过程, 难调试和扩展,没有移植性
        正确锁类型                # 隐式锁、显式锁、行锁、页锁、范围锁、表锁、数据库锁
        全球化用utf-8,要使用表情,用utfmb4
            SELECT LENGTH("轻松工作") 返回 12
            SELECT CHARACTER_LENGTH("轻松工作") 返回4
    事务
        不要多阶段提交             # 更好的拆分表,而不多阶段提交延长单一数据库生命
        避免大事务
        连接释放
    crud
        TRUNCATE快,但无事务不触发trigger, 不要在开发代码中使用
        修改数据时,先select,避免误删除和修改
        分页时count为0直接返回
        用覆盖索引来变相加快查询,如explain的结果,命中时出现using index
        避免返回大量数据
        order by注意利用索引的有序性,order by最后的字段是组合索引的最后,避免file_sort
            如 where a=? and b=? order by c; 索引 a_b_c
            有范围查找时,有序性无法利用,如 where a>10 order by b
    联合
        多表联合查询拆分多个query     # 容易锁表和阻塞
        禁止三表join
            join的字段类型要一致
            被关联的字段需要有索引
            注意sql性能
        join时,小结果驱动大结果      # left join小表在左
            优化前
                select * from admin
                left join log on admin.admin_id = log.admin_id
                where log.admin_id>10
            优化后
                select * from
                    (select * from admin where admin_id>10) T1
                left join log on T1.admin_id = log.admin_id
mysql
    引擎选择
    limit 1
        只查一条时,加limit 1, 引擎会找到一条马上返回
    limit基数大用between, 分页时要找到id, 避免offset之前全查的问题
        优化前
            select * from admin order by id limit 10000,10
        优化后
            select * from admin where id between 10000 and 10010 order by id
        子查询id
            select a.* from 表1 a, (select id from 表1 where 条件 limit 100000,20) b where a.id=b.id

nosql #

介绍
    aggregate-oriented (面向聚合)
        键值
        文档
        列族
    relationship-oriented (面向关系)
        图
特点
    少约束(schemaless)
    应用程序数据库(作为微服务的数据库来解耦)
    聚合(aggregate)
        # 领域驱动设计中提出
        # 图除外
    图支持事务
    牺牲一部分一致性和持久性
问题
    存在不一致窗口
    会话一致性问题
兼容
    物化视图来处理更新
    实时BI, 来更新中间关系聚合
    一致性
        锁
        条件更新(更新前检查)
            版本戳
                # http 中的etag
        写入仲裁与读取仲裁
            复制因子大于某值时认为写入完成
            读取多于某值个节点数据并相同时,认为读到最新数据
        用zookeeper等外部“事务”程序库同步读写操作

#

介绍
    领域
    关系是一等公民
    大部分不支持分布式
    Gremlin,Cypher 查询语言
适用
    互联数据
    运输等基于位置的服务
    推荐引擎
不适用
    经常更新
工具
    flockDB
            # 仅支持单深度关系及邻接表
    hyperGraphDB
    infiniteGraph
    allegroGraph
    orientdb
    pregel
        # google图数据库

neo4j #

介绍
    使用zookeeper
特点
    完全兼容ACID
    主从复制
    副本从节点
        从节点写数据,先同步到主节点, 再由主节点分发

配置 dbms.connector.bolt.enabled=true dbms.connector.bolt.listen_address=0.0.0.0:7687 dbms.connector.http.enabled=true dbms.connector.http.listen_address=0.0.0.0:7474 # 远程访问 cql 数据类型 boolean byte # 8位整数 short # 16位整数 int # 32位整数 long # 64位整数 float # 32位浮点数 double # 64位浮点数 char # 16位字符 string 命令 create # 创建, 自动生成属性, 最大约为35亿 CREATE (dept:Dept:Dept2 { deptno:1,name:“a”}) # 节点名:多标签 {属性} CREATE (p1:Profile1)-[r1:LIKES]->(p2:Profile2) # 2节点,1关系

...

Mongodb

特点 #

    数据结构json(bson)
    易写入,易修改
    c++编写
    分布式
    介于关系数据库 和 非关系数据库之间
    查询语句强
    支持索引
    bson格式

注意 #

    document不能大于4Mb
    可以非安全模式异步马上成功
    每个连接用队列存储命令

数据结构定义 #

    collection                                        # 表
            document                                # 记录
                    field(key, value)                # 字段(field)与值(value)
    与关系型数据库的区别
            document中的field不要key俱全或一样
            find()命令查询

bson的数据类型 #

    #bson 是json的扩展
     # 增加了数据类型
     # 把json数据转换成二进制码存到文件
    null
    boolean
    undefined
    数组                                # 如{gps: [20, 56]}
    32位和64位整数                # shell中不支持
                                    ## node.js python java等高级语言的驱动中支持
    64位浮点                        # shell使用的全是这种类型, 如{x:3.14}
    utf-8                                # 字符串类型
    ObjectID
    Date                                # 如{x:new Date()}
    正则                                # 如{x:/uspcat/i}
    javascript块代码                # 如{x:function(){}}
                                    ## 相当于存储过程
    内嵌文档                        # 如{x: {xx: "a"}}
    二进制                                # shell中不能使用

ObjectId #

    大小
            12字节
            显示为24个十六进制字符
            # 空间换时间的思想
    细节
            前4字节是unix时间戳
            后3字节集群machine hash
            后2字节pid
            后3字节inc自增计数器, 在前面都相等时全局自增

命名 #

    数据库与集合名
            不能是空字符串
            特殊字符
                    ' (空格) , $ / \ \0
            应该全小写
            小于64字节
            数据库名不与保留库名相同,如
                    admin, local, config
    集合名
            db-text合法,但不能db.db-text得到,要db.getCollection("db-text").text得到
                    # db-text 会认为是减法
                    ## 数据库名可以是db-text
            可以a.b来命名来划分子集合
                    不能以system.开头命名

api #

collection
        增
                save
                        # 不存在时插入,存在时更新
                        # {$ref: 'user', $id: 1} 来保存引用
                insert
        删
                remove('id': 'bar')        # 删除一条数据
                                                                        #remove()删除所有数据
                drop()                                # 删除persons collection, 不释放文件空间
                dropIndexes()                        # 删除所有索引
        改
                update(finder, updater, options或upser, multi)
                        # $set
                        # {age: {$gt: 18}, $isolated : 1} $isolated事务隔离该字段到本语句执行结束, does not work with sharded clusters
                findAndModify
        查
                findOne()
                find(finder, filter)
                        # limit(3).skip(10).sort({name: -1, age: 1})
                        ## sort({$natural: 1}) 固定集合排序
                        # explain() 返回带统计信息的文档
                        ## 是否用到索引,耗时,需要扫描多少文件
                        # hint({}) 强制使用某索引查询
                        # null可以匹配null, 也可以匹配{$exists: false}        
                        # 正则可以匹配自身,也可以模式字符串
                count()                                # document的条数
                aggregate

db
        # 默认存在的数据库admin, config, local
        sources
                # 从节点中设置的源collection
        help()
        persons.help()
                # 显示某集合的帮助
        auth('username', 'pwd')
                # 切换用户
        addUser()
                # addUser('admin', 'asdf')
                # addUser('readonly', 'asdf', true)
        listCommands()
        shutdownServer()
        eval()
                # 执行
        stats()                                        
                # 当前数据库的状态
                ## 包括名称,collection数,索引数等
        createCollection()
                # {'user', {capped: true, size: 100, max: 10}} 
                ## 创建固定集合, 100字节, 文档数上限为10
                ## 固定集合插入快,不能删除,无_id, 有尾部游标
        getCollection("persons").text
                # 同db.persons        
        dropDatabase()
                # 删除当前数据库        
        repairDatabase()
                # 释放空间
        serverStatus()
                # 返回数据库的metrics 数据
        serverStatus().metrics.cursor
                # 返回指针信息
        ensureIndex({x: 1, y: -1}, {name: 'xy'})
                # 建立x的升序, y的降序联合索引
                # 只使用索引的前部, 即对x的查询可以用该索引
                # {"gps": '2d'} {'gps': '2dsphere'}
                ## 支持gps写成 [0, 0] {x: 0, y: 0} {latitude: 0, longitude: 0} 格式
                # 可以索引内嵌文档
                # {unique: true} 来建立唯一索引
                # {dropDups: true} 将唯一索引中重复的文档都删掉
        dropIndexes
        system
                indexes
                        # 保留集合,索引
                namespaces
                        # 也包含索引信息
                js
                        insert({_id: 'fn', value: function() {}})
                                # 用db.eval('fn()') 执行
        runCommand()
                # {'dropIndexes': 'col', 'index': 'ind'}
                # 可以返回命名执行的状态信息
                {buildInfo: 1}
                {collStats: 'user'}
                {distinct: 'user', key: a, query: {b: 0}}
                {drop: 'user'}
                {dropDatabase: 1}
                {dropIndexes: 'user', index: 'ind'}
                {getLastError: 1}
                        # 上次更新的作用信息
                        {getLastError: 1, w: 3}
                                # 阻塞复制,有3个节点
                {isMaster: 1}
                {findAndModify: 'user', query: {a: 0}, sort: {a: 1}, update: {$set: {a: 1}}}
                {listCommands: 1}
                {listDatabases: 1}
                {ping: 1}
                {renameCollection: 'user', to: 'user1'}
                {repairDatabase: 1}
                        # 修复并压缩当前数据库
                {serverStatus: 1}
                        # globalLock: 全局写入锁占用了多少时间
                        # mem: 内存映射了多少数据
                        # indexCounters: B树磁盘检索(misses)和内存检索(hits)的次数
                        # backgroundFluhing: 后台做了多少次fsync及用的时间
                        # opcounters: 每种主要操作的次数
                        # asserts: 断言的次数
                {convertToCapped: 'user', size: 100}
                        # 转为固定集合
                {fsync: 1, lock: 1}
                        # 缓冲写入磁盘,并加写入锁。后可以直接复制磁盘数据来备份
                        # db.$cmd.sys.unlock.findOne() 解锁
                        # db.currentOp() 查看为空时已解锁
                {resync: 1}
                        # 从节点重新同步
                {collMod: 'users', usePowerOf2Sizes: true}
                        # 每次增大空间总是2的倍数,适用于常写的集合
rs
        isMaster
        slaveOk
dcl
        help                                        # 显示帮助
        show dbs                                # 显示所有数据库
        use mydb                                # 选择数据库(默认为test)
                                                ## 如果没有该数据库,则创建(插入第一条数据时实际创建)
        db                                        # 显示当前数据库名
        show collections                        # 查看当前数据库的collections
        db.eval()                                # 执行shell语法字符串

        用户管理命令
                use test                                # 选择需要添加用户的数据库
                db.addUser('name','pwd')                # 第三个参数代表是否只读 true代表是 ,  false代表否
                                                        ## db 代表本数据库,也就是test
                db.system.users.find()                        # 查看用户列表
                db.auth('name','pwd')                # 用户认证,反回1代表认证成功
                db.removeUser('name')
                show users                                # 查看所有用户

                        # 注
                                权限生效需要mongod 以 -auth参数启动
                                admin数据库中的user是超级管理员 , 其他数据库中的user只限于本数据库

ttl(time to live)
        # mongodb每1分钟检查一次数据删除
        db.log_events.ensureIndex({"createdAt": 1}, {expireAfterSeconds: 3600 })
        db.log_events.insert({
                "createdAt": new Date(),
                "logEvent": 2,
                "logMessage": "Success!"
        })
                # 插入的这条数据在1小时后删除
        db.log_events.ensureIndex({"expireAt": 1}, {expireAfterSeconds: 0})        
        db.log_events.insert({
                "expireAt": new Date('July 22, 2013 14:00:00'),
                "logEvent": 2,
                "logMessage": "Success!"
        })
                # 插入的这条数据在July 22, 2013 14:00:00删除

aggregate #

mapReduce(
        function() {emit(this.cust_id, this.amount);},
                # map
        function(key, values) {return Array.sum(values)},
                # reduce
        {
                query: {status: 'A'},
                        # query
                out: 'order_totals'
                        # output
        } 
)

distinct()

count()

group({
        key: {a: 1},
                # $keyf: function(x) {return x.category} 定义分组函数
        cond: {a: {$lt: 3}}.
        $reduce: function(cur, result) {result.count += cur.count},
        initial: {count: 0},
        finalize: function (prev) {}
})
        # 返回的文档 {retval: [], count: 0, keys: 0, ok: 0}
aggregate([
        {$redact: {$cond: {
                if: {$eq: ['$level', 5]},
                then: '$$PRUNE',
                else: '$$DESCEND'
        }}}
        {$match: {status: 'A'}},
        {$geoNear: {...}},
        {$project: {name: {$toUpper: '$_id'}, _id: 0}},
        {$unwind: '$sizes'},
        {$group: {_id: '$state', totalPop: {$sum: '$pop'}}},
        {$skip: 10},
        {$limit: 5},
        {$sort: {age: -1}},
        {$out: 'authors'}
])

例子
    o-> 得到tags数组的长度
    db.users.aggregate([{
            $group: {
                    _id: '$username',
                    tags_count: {$first: {$size: '$tags'}}
            }
    }])
    db.users.aggregate([{
            $project: {
                    tags_count: {$size: '$tags'}
            }
    }])

expressions #

$and
$or
$not
$setEquals
$setIntersection
$setUnion
$setDefference
$setIsSubset
$anyElementTrue
$allElementsTrue
$cmp
$eq
$gt
$gte
$lt
$lte
$ne
$add
$subtract
$multiply
$divide
$mod
$concat
$substr
$toLower
$toUpper
$strcasecmp
$meta
$size
$map
$let
$literal
$dayOfYear
$dayOfMonth
$dayOfWeek
$year
$month
$week
$hour
$minute
$second
$millisecond
$dateToString
$cond
$ifNull
$sum
$avg
$first
$last
$max
$min
$push
$addToSet
$near
$within
$box
$center

对象 #

全局函数
        printjson
        connect('localhost:27017/mydb')
                # 连接另一个服务器
        runProgram
对象类型
        cursor
                hasNext()
                        # 立即返回前100个数据与4Mb数据的较小者。取数据时直接读缓存
                next()
                forEach

复制 #

复制
        mongod --master --oplogSize 100
        mongod --slave --source localhost:27017
                # --source指定主节点
                # --only 指定只复制特定的数据库
                # --slavedelay 主从复制时的延时
                # --fastsync 从节点是主节点快照时,加这个选项,同步速度快
                # --autoresync 重新同步
                # --oplogSize 主节点oplog的大小
        db.sources.insert({host: 'localhost:27017'})
                # 从节点设置主节点

副本集
        #  没有主节点,集群自己选举主节点
        # 数据太多从节点会自动停止同步
        mongod --dbpath '/var/local/mongo1' --port 27017 --replSet rs0
                # 三个实例replSet 名必叫 rs0
        use admin
        rs.initiate({
                _id: 'a',
                members: [{
                        _id: 1,
                        host: 'localhost1:27017'
                }, {
                        _id: 2,
                        host: 'localhost1:27018'
                }]
        })
                # 其中一台执行初始化
        rs.add('localhost:27019')
        rs.status()
        db.getMongo().setSlaveOk()
        rs.isMaster()
        rs.conf()
        db.getReplicationInfo()
        db.printReplicationInfo()
        db.printSlaveReplicationInfo()
        use local        
        db.addUser('name', 'pwd')
                # 复制认证时用

分片 #

mongods --port 3000 --configdb localhost:27017
        # 多个地址用,隔开
        # 每个片都就是副本集
mongo localhost:3000/admin
db.runCommand({addshard: 'localhost:27017‘, allowLocal: true})
        # 在localhost上运行时, 要设allowLocal
        # 'a/localhost:27017' 让mongo知道这个片所在的副本集
db.runCommand({enablesharding: 'db1'})
db.runCommand({shardcollection: 'db1.user', key: {_id: 1}})
db.printShardingStatus()
db.runCommand({removeshard: 'localhost:27017'})

shell #

mongo 127.0.0.1:27017/admin
        # 启动sell , 默认数据库为test
mongod –port 10000 –fork –logpath= logpath=/data/mongodb/log/mongodb.log -- logappend -- dbpath=/data/mongodb/data/db –config ~/.mongodb.conf 
        # 启动服务 -auth开启身份验证
        # --rest 开启http管理,其端口号比mongo端口号大1000
        ## --nohttpinterface关闭http管理
        # --bindip localhost 设置只能有某ip访问
        # --noscripting 完全禁止服务端js执行
        # --repair 启动并修复
        # 不要发送SIGKILL信号关闭(kill -9), 应发送SIGINT或SIGTERM
        mongod --remove                                
                # 结束服务
        // mongodb.conf
                port = 5586
                fork = true
                logpath = mongodb.log
mongodump --host 127.0.0.1 --port 27017 --out ./dir/name
        # 备份数据库
mongodump -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -o 文件存在路径
mongorestore --host 127.0.0.1 --port 27017 --directoryperdb ./dir/name
        # mongorestore -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 --drop 文件存在路径
        # --drop 是先删除现有的数据
mongoexport -d tank -c users -o /home/outrun/mongo
        # 导出整张表
        ## mongoexport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表名 -f 字段 -q 条件导出 --csv -o 文件名
        # mongoexport -d tank -c users --csv -f uid,name,sex -o tank/users.csv 
        ## 导出表的部分字段
        # mongoexport -d tank -c users -q '{uid:{$gt:1}}' -o tank/users.json
        ## 根据条件导出数据
mongoimport -d tank -c users --upsert tank/users.dat
        # mongoimport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表名 --upsert --drop 文件名 
        ## 还原整表导出的非csv文件,  --upsert 表示插入或更新现有数据
        # mongoimport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表名 --upsertFields 字段 --drop 文件名
        ## 还原部分字段导出的文件, --upsertFields跟upsert一样
        ## 如 mongoimport -d tank -c users  --upsertFields uid,name,sex  tank/users.dat
        # mongoimport -h IP --port 端口 -u 用户名 -p 密码 -d 数据库 -c 表名 --type 类型 --headerline --upsert --drop 文件名  
        ## 还原导出的csv文件
        ## mongoimport -d tank -c users --type csv --headerline --file tank/users.csv
mongofiles put foo.txt
        # 使用gridfs
        list
        get foo.txt
        search
                # 按文件名查找
        delete foo.txt
mongostat
        # 实时输出mongo状态

java client #

1.导入mongo-java-drver-2.9.3.jar
2.api
        Mongo m = new Mongo("localhost", 27017);
        DB db = m.getDB("mydb");
        boolean auth = db.authenticate("root", "root".toCharArray());
        System.out.println("身份认证" + auth);
        // 获得所有数据库名
        for (String s : m.getDatabaseNames()) {
                System.out.println("db : " + s);
        }
        // 删除数据库
        m.dropDatabase("my_new_db");
        // 获得collection列表
        Set<String> colls = db.getCollectionNames();
        for (String s : colls) {
                System.out.println("collection : " + s);
        }
        // 获得一个collection
        DBCollection coll = db.getCollection("testCollection");
        // 创建document(包括内嵌文档)
        DBObject doc = new BasicDBObject().append("appendField", "appendField");
        doc.put("name", "MongoDB");
        doc.put("type", "database");
        doc.put("count", 1);
        DBObject info = new BasicDBObject();
        info.put("x", 203);
        info.put("y", 102);
        doc.put("info", info);
        // 插入文档
        coll.insert(doc);
        // 查询文档
        DBObject doc2 = coll.findOne();
        System.out.println(doc2);
        // 统计文档数
        long count = coll.getCount();
        System.out.println(count);
        // 用游标遍历
        DBCursor cursor = coll.find();
        while (cursor.hasNext()) {
                DBObject object = cursor.next();
                System.out.println(object);
        }
        // 查询
        DBObject query = new BasicDBObject();
        query.put("i", 71);
        cursor = coll.find(query);
        // 条件查询
        query = new BasicDBObject();
        query.put("i", new BasicDBObject("$gt", 50)); // i>50
        cursor = coll.find(query);
        // 创建索引
        coll.createIndex(new BasicDBObject("i", 1)); // 1代表升序 , -1是降序
        // 查询索引
        List<DBObject> list = coll.getIndexInfo();
                for (DBObject index : list) {
                System.out.println("索引 : " + index);
        }
类型
    // 自动生成的唯一ID
    ObjectId id = new ObjectId();
    System.out.println(id);

Postgre SQL

命令 #

initdb                          # 初始化数据库
    --locale en_US.UTF-8 
    -D 'data'
postgres                        # 启动数据库
    -D 目录
    -p 6543
pg_ctl start                    # 控制数据库: start, stop等
    -D data 
    -l a.log 
postmaster
    -D /data
psql
    -d db1
    -h localhost 
    -p 5432
    -U 用户名
    -W                          # 强制要求验证密码
    -f 导入sql命令文件, 或者在末尾加 < a.sql 来导入
    -L 导出日志文件

    o->
    psql -U outrun -f pg.sql db1                    # 导入数据
pg_dump                         # 导出数据库
    -f                          # 指定文件
    -U                          # 用户
    -E UTF8                     # 编码
    -h localhost
    -n public                   # 指定schema
    -a                          # 只导数据,没有schema
    -F t                        # 压缩成tar

    o->
    pg_dump -U outrun -f pg.sql db1                 # 导出数据, -t tb1 导出表
pg_restore
    o->
    pg_restore -U outrun -d db1 pg.tar              # 导入压缩的数据
createdb                        # 创建数据库并指定 owner
    -hlocalhost -Upostgres -O 用户名 数据库名                        
dropdb
    -U user dbname

特色sql #

元命令
    \?                          # postgre命令
    \h                          # sql命令
    \l                          # 列出数据库
    \q                          # 退出
    \c 数据库名                 # 切换数据库
    \d name                     # 查看序列、表、视图、索引
        \dS+                    # 详情
    \du                         # 查看角色
    \dt                         # 查看所有表
        \dtS+                   # 详情
    \ds                         # 查看序列
    \i a.sql                    # 执行sql文件
    \o a.log                    # 日志文件
    \password                   # 更换密码
    \x                          # 开启/关闭竖排显示

    [sql] \gdesc                # 快速显示结果列名和类型
数据类型
    serial                      # 4字节,自增序列
        bigserial               # 8字节
    text default ''::text
    bigint default 0            # 8字节
        smallint                # 2字节
        int, integer            # 4字节
        decimal                 # 变长, 声明精度,精确
        numeric                 # 同上
        float
        real                    # 4字节,变精度,不精确
        double precision        # 8字节,变精度,不精确

    boolean default false
    text[]                      # text数组
    date
    time
    timestamp with time zone
    interval
    
    bytea                       # 二进制

    money
    uuid
约束
    constraint user_id primary key (id)
    constraint user_m_id unique(m_id)
    constraint fk_b_id foreign key (b_id) references tbb(id)
        MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE NO ACTION
dcl
    create database db1
        owner outrun
    create user 'outrun' with password 'asdf'
    create role 用户名 with password '密码' login
        # 创建用户。role关键词可以省略

    drop database db1
    drop table tablename;

    alter database abc RENAME TO cba;
    alter database 数据库名 owner to 用户名
        # 更改数据库 owner
    alter table tb 
        add primary key (id)
        add foreign key(b_id) references tb(id) on update cascade on delete cascade
        add column c1 text
        alter column id type int using id::integer
        rename c1 to c2
            drop constraint fk_b_id foreign key (b_id) references tbb(id)
        drop [column] name
        owner to outrun
            # 更改表 owner
    
    alter role 用户名 with login                     # 添加权限
        password 'asdf'                             # with password 'asdf', 修改密码
        VALID UNTIL 'JUL 7 14:00:00 2012 +8'        # 设置角色有效期
        login, superuser, createdb, createrole, replication, inherit

    grant all privileges on database 数据库名 to 用户名
        # 授权数据库权限
ddl 
    insert into tb("desc") values ('a'); 
模糊查询
    ~                       # 匹配正则,大小写相关
        除'a$' '^a'的正则都只适合pg_trgm的gin索引
    ~*                      # 匹配正则,大小写无关
    !~                      # 不匹配该正则
    !~*
    ~ '^a'
        like 'a%'
    ~ 'a$'
    ~ 'ab.c'
        like '%ab_c%'

o-> 视图 
CREATE VIEW myview 
AS 
SELECT city, temp_lo, temp_hi, prcp, date, location 
FROM weather, cities 
WHERE city = name;

o-> 建表
create table dwh_timestamp_meta
(
"id" serial NOT NULL,
"id" serial primary key,
"c_id" serial references cities(id),
"mongo_document_name" text default ''::text,
"last_update_time" bigint default 0,
"execute_time" timestamp with time zone,
constraint pk_id primary key(id)
)
with (
oids=false
);

o-> 序列
create table a(
    id bigint primary key
);
create sequence a_id_seq
    start with 1
    increment by 1
    no minvalue
    no maxvalue
    cache 1;
alter table a alter column id set default nextval('a_id_seq')

数据字典 #

pg_roles                        # 角色信息
pg_database                     # 数据库信息
information_schema
    select column_name from information_schema.columns where table_schema='public' and table_name='ad';
        # 表的所有列名
pg_stat_user_tables
    select relname from pg_stat_user_tables;
        # 所有表名
pg_stat_activity                # 活动状态
    SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE datname='garbage' AND pid<>pg_backend_pid();
        # 查看数据库活动连接

配置 #

数据库目录
    /usr/lib/systemd/system/postgresql.service
jdbc
    driver : org.postgresql.Driver
    url : jdbc:postgresql://localhost:5432/postgres
    初始用户名 : postgres
    初始数据库 : postgres

存储过程 #

drop function change_type1();
create or replace function change_type1()
returns int as
$body$
DECLARE
    r mongo_keys_type%rowtype;
    begin
    for r in select * from mongo_keys_type where type='number'
    loop
        EXECUTE 'alter table "' || r."mongo_collection_name" || '" alter "' || r."key" || '" type decimal';
    END LOOP;
    return 0;
    end
$body$
language 'plpgsql';

select change_type1()

案例 #

授权
    grant all privileges on database 'db1' to 'outrun'
    alter role 'outrun' createdb
    alter role 'outrun' superuser
创建用户
    create user 'outrun' with password 'asdf'
    create role 'outrun' createdb password 'asdf' login
修改密码
    alter user 'outrun' with password 'asdf'