Postgresql学习记录

pg sequence 相关操作

查询序列的相关信息

1
select * from pg sequence where segrelid = 'seq_name'::regclass;

修改序列的类型为 bigint

1
alter sequence "seq_name" as bigint MAXVALUE 9223372036854775807;

查询 表的序列名

1
select pg_get_serial_sequence('table_name','column_name');

shell命令总结

1
sed -i '/master/a\config' test

在匹配到 master 字符串的那一行的下一行 插入 config

JAVA lambada表达式查询分组中的最大值

查询出每个班级年龄最大的学生和年龄最小的学生

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//
public class MaxByMinBy {
public static void main(String[] args) {
Student student = new Student("Bruce", 27, "A");
Student student1 = new Student("Michael", 23, "A");
Student student2 = new Student("Lee", 22, "B");
Student student3 = new Student("Lucy", 25, "B");
List<Student> students = Arrays.asList(student, student1, student2, student3);
Comparator<Student> ageComparator = Comparator.comparing(Student::getAge);
// 查询年纪最小 使用 minBy
Map<String, Optional<Student>> collect = students.stream().collect(Collectors.groupingBy(Student::getClassName, Collectors.reducing(BinaryOperator.maxBy(ageComparator))));
collect.forEach((k, v) -> System.out.println("Class:" + k + " Age:" + v.get().getAge() + " Name:" + v.get().getName()));
}

@Data
@AllArgsConstructor
static class Student {
private String name;
private Integer age;
private String className;

}
}

运行结果

1
2
Class:A Age:27 Name:Bruce
Class:B Age:25 Name:Lucy

docker更改默认存储位置

docker 容器默认安装在系统盘,一般情况下系统盘比较小,随着镜像和容器的不断增加,可能回出现容量不够的情况,所以需要手动指定 docker 相关文件的存储位置

编辑 /etc/docker/daemon.json 文件

1
vi /etc/docker/daemon.json 

增加相关配置

1
2
3
4
{
"registry-mirrors": ["http://hub-mirror.c.163.com"],
"data-root": "/www/docker"
}

其中 registry-mirror 指定镜像仓库的源

data-root 指定镜像和容器的存储路径

保存之后重启 docker

1
systemctl restart docker

设计模式设计原则

  • 单一职责原则(Single Responsibility Principle,SRP)

    一个类只负责一个功能领域中的相应职责。或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。

  • 开闭原则(Open-Closed Principle,OCP)

    一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。

  • 里氏替换原则(Liskov Substitution Principle,LSP)

    所有引用基类(父类)的地方必须透明地使用其子类对象。

    里氏替换原则表名,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来不成立,如果一个软件实体使用的是一个子类对象的话,那么它一定能够使用基类对象。

  • 依赖倒置原则(Dependency Inversion Princople,DIP)

    抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口变成,而不是针对实现编程。

    以来倒置原则要求在程序代码中传递参数时或在关联关系中,尽量引用高层次的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型转换等,而不要用具体类来做这些事情。

    开闭原则目标里氏代换基础依赖倒置原则手段,它们相辅相成。

  • 接口隔离原则(Interface Segregation Principle,ISP)

    使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

  • 合成复用原则(Composition/Aggregate Reuse Principle,CARP)

    尽量使用对象组合,而不是继承来达到复用的目的

  • 迪米特法则(Law of Demeter,LoD)

    一个软件实体应当尽可能少地与其他实体发生相互作用。

MysqlExplain的type字段

join type

mysql 使用 explain 命令进行分析时 type 字段会有下面几种 join type类型

查询效率由好到差

  • system

    这个表只有一行(这个表是系统表),这是 join type = const 的一种特殊形式

    1
    2
    3
    4
    EXPLAIN SELECT
    *
    FROM
    `mysql`.`proxies_priv`

    查询结果如下

    | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    | —- | ———– | ———— | ———- | —- | ————- | —- | ——- | —- | —- | ——– | —– |
    | 1 | SIMPLE | proxies_priv | system | | | | | 1 | 100 | | |

  • const

    表中只有一行匹配的数据,在 where 条件中和所有

    1)主键

    2) 唯一键

    进行比较时会用到 const

    比如有如下表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    CREATE TABLE `tb_name` (
    `pp1` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
    `pp2` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
    `f3` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
    `f4` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
    UNIQUE KEY `pp1` (`pp1`,`pp2`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

    INSERT INTO `db02`.`tb_name`(`pp1`, `pp2`, `f3`, `f4`) VALUES ('1', '2', '3', '4');
    INSERT INTO `db02`.`tb_name`(`pp1`, `pp2`, `f3`, `f4`) VALUES ('2', '3', '4', '5');

    执行如下查询

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    EXPLAIN SELECT
    *
    FROM
    `tb_name`
    WHERE
    pp1 = '1'
    AND pp2 = '2'
    ## 或者
    EXPLAIN SELECT
    *
    FROM
    `tb_name`
    WHERE
    pp2 = '2'
    AND pp1 = '1'
    都会使用 const

    结果如下

    | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    | —- | ———– | ——- | ———- | —– | ————- | —- | ——- | ———– | —- | ——– | —– |
    | 1 | SIMPLE | tb_name | | const | pp1 | pp1 | 2046 | const,const | 1 | 100 | |

  • eq_ref

    前表的每一行,在后表中只有一行被扫描

    One row is read from this table for each combination of rows from the previous tables.

    有如下两张表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    CREATE TABLE `students` (
    `id` int(11) NOT NULL,
    `name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
    `age` int(3) DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

    INSERT INTO `db02`.`students`(`id`, `name`, `age`) VALUES (1, '张三', 23);
    INSERT INTO `db02`.`students`(`id`, `name`, `age`) VALUES (2, '李四', 33);

    CREATE TABLE `scores` (
    `user_id` int(11) NOT NULL,
    `score` int(255) DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;\
    INSERT INTO `db02`.`scores`(`user_id`, `score`) VALUES (1, 100);



    EXPLAIN SELECT
    *
    FROM
    students t1,
    scores t2
    WHERE
    t1.id = t2.user_id


    可见 scores 表中只有一条数据,结果如下,

    | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    | —- | ———– | —– | ———- | —— | ————- | ——- | ——- | ————— | —- | ——– | —– |
    | 1 | SIMPLE | t2 | | ALL | PRIMARY | | | | 1 | 100 | |
    | 1 | SIMPLE | t1 | | eq_ref | PRIMARY | PRIMARY | 4 | db02.t2.user_id | 1 | 100 | |

    如果再往 score 表中 插入一行数据,则会变为全表扫描

  • ref

    非唯一性索引扫描,返回匹配某个单独值的所有行. 这个索引

    1) 不是 主键 也不是 唯一键

    或者

    2)使用最左匹配原则进行匹配

    ref 虽然使用了索引,但是查询结果并不唯一,但是并不需要扫描全表,因为索引时有序的

    有如下两个表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    CREATE TABLE `tb_ref` (
    `f1` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
    `f2` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
    `f3` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
    `f4` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
    KEY `index_tb_ref_f1` (`f1`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
    ## 一定要多添 `tb_ref` 一定要多添加几条数据,如果数据太少 mysql 直接会使用全表扫描 type=ALL
    INSERT INTO `tb_ref`(`f1`, `f2`, `f3`, `f4`) VALUES ('1', '2', '3', '4');
    INSERT INTO `tb_ref`(`f1`, `f2`, `f3`, `f4`) VALUES ('2', '2', '3', '4');
    INSERT INTO `tb_ref`(`f1`, `f2`, `f3`, `f4`) VALUES ('2', '2', '3', '4');
    INSERT INTO `tb_ref`(`f1`, `f2`, `f3`, `f4`) VALUES ('2', '2', '3', '4');
    INSERT INTO `tb_ref`(`f1`, `f2`, `f3`, `f4`) VALUES ('2', '2', '3', '4');
    INSERT INTO `tb_ref`(`f1`, `f2`, `f3`, `f4`) VALUES ('2', '2', '3', '4');
    INSERT INTO `tb_ref`(`f1`, `f2`, `f3`, `f4`) VALUES ('2', '2', '3', '4');
    INSERT INTO `tb_ref`(`f1`, `f2`, `f3`, `f4`) VALUES ('2', '2', '3', '4');
    INSERT INTO `tb_ref`(`f1`, `f2`, `f3`, `f4`) VALUES ('2', '2', '3', '4');
    INSERT INTO `tb_ref`(`f1`, `f2`, `f3`, `f4`) VALUES ('2', '2', '3', '4');


    CREATE TABLE `other_table` (
    `ref_f1` varchar(255) COLLATE utf8mb4_bin NOT NULL,
    `age` int(3) DEFAULT NULL,
    `name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;

    INSERT INTO `other_table`(`ref_f1`, `age`, `name`) VALUES ('1', 22, '张三');
    INSERT INTO `other_table`(`ref_f1`, `age`, `name`) VALUES ('1', 23, '张1三');
    INSERT INTO `other_table`(`ref_f1`, `age`, `name`) VALUES ('2', 23, '张1三');
    INSERT INTO `other_table`(`ref_f1`, `age`, `name`) VALUES ('2', 23, '张1三');
    INSERT INTO `other_table`(`ref_f1`, `age`, `name`) VALUES ('2', 23, '张1三');
    INSERT INTO `other_table`(`ref_f1`, `age`, `name`) VALUES ('2', 23, '张1三');
    INSERT INTO `other_table`(`ref_f1`, `age`, `name`) VALUES ('2', 23, '张1三');
    INSERT INTO `other_table`(`ref_f1`, `age`, `name`) VALUES ('2', 23, '张1三');
    INSERT INTO `other_table`(`ref_f1`, `age`, `name`) VALUES ('2', 23, '张1三');

    执行如下语句

    1
    2
    3
    4
    5
    6
    EXPLAIN SELECT
    *
    FROM
    tb_ref
    WHERE
    f1='1'

    结果如下:

    | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    | —- | ———– | —— | ———- | —- | ————— | ————— | ——- | —– | —- | ——– | —– |
    | 1 | SIMPLE | tb_ref | | ref | index_tb_ref_f1 | index_tb_ref_f1 | 1023 | const | 1 | 100 | |

    执行如下语句

    1
    2
    3
    4
    5
    6
    7
    EXPLAIN SELECT
    *
    FROM
    tb_ref t1,
    other_table t2
    WHERE
    t1.f1 = t2.ref_f1

    返回结果

id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t2 ALL 9 100
1 SIMPLE t1 ref index_tb_ref_f1 index_tb_ref_f1 1023 db02.t2.ref_f1 1 100
  • range

    range 是范围扫描,当比较索引列包含

    1
    =, <>, >, >=, <,<=, IS NULL, <=>, BETWEEN, LIKE, or IN() 

    时,可能产生 range

    Only rows that are in a given range are retrieved, using an index to select the rows. The key column in the output row indicates which index is used. The key_len contains the longest key part that was used. The ref column is NULL for this type. range can be used when a key column is compared to a constant using any of the =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, LIKE, or IN() operators: SELECT FROM tbl_name WHERE key_column = 10; SELECT FROM tbl_name WHERE key_column BETWEEN 10 and 20; SELECT FROM tbl_name 1351 EXPLAIN Output Format WHERE key_column IN (10,20,30); SELECT FROM tbl_name WHERE key_part1 = 10 AND key_part2 IN (10,20,30);

覆盖索引(covering index)

理解方式一:就是select的数据列只从索引中就能取得,不必读取数据行,mysql可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,欢聚话说查询列要被所建的索引覆盖。

理解方式二:索引是高校找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取真个行,毕竟索引的叶子节点存储了它们索引的数据;当能通过读取索引你就可以得到想要的数据,那就不需要读取行了。一个索引包含了(或覆盖了)满足查询结果的数据就叫索引。

注意:

如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可 select *,

因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降。

explan 分析执行顺序的例子

来自尚硅谷的例子

HashMap面试题

问题一

为什么容量一定是2的幂?

1
hash & (length-1)

如果 length = 16,则 length-1 = 15=1111;

如果hash 是一个32 位的整数,最后四位是 1001

…. …. …. 1001

& 1111

​ 1001

所以使用这种按位与的方法很容易,求出 hash % length 的值

JAVA 8 HashMap的改进

数组+链表/红黑树

扩容时插入顺序的改进

函数方法

​ forEach

​ compute系列

Map的新Api

​ merge

​ replace

正则表达式相关

提取中括号中间的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String s = "[102.8164002309, 24.9892758419], [102.8165296922, 24.9887447331], [102.8168627242, 24.9887980873], [102.8169049102, 24.9890462091], [102.816831012, 24.989382232], [102.8166749033, 24.9893820851], [102.8164002309, 24.9892758419]";
// 包含中括号
Pattern pattern = Pattern.compile("(\\[.*?])");
// 不包含中括号
Pattern pattern1 = Pattern.compile("\\[(.*?)]");

Matcher matcher = pattern.matcher(s);
while (matcher.find()) {
System.out.println(matcher.group(1));
}
System.out.println("------------------------");
Matcher matcher2 = pattern1.matcher(s);
while (matcher2.find()) {
System.out.println(matcher2.group(1));
}
}

打印结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[102.8164002309, 24.9892758419]
[102.8165296922, 24.9887447331]
[102.8168627242, 24.9887980873]
[102.8169049102, 24.9890462091]
[102.816831012, 24.989382232]
[102.8166749033, 24.9893820851]
[102.8164002309, 24.9892758419]
------------------------
102.8164002309, 24.9892758419
102.8165296922, 24.9887447331
102.8168627242, 24.9887980873
102.8169049102, 24.9890462091
102.816831012, 24.989382232
102.8166749033, 24.9893820851
102.8164002309, 24.9892758419

mysql-groupby报错

mysql groupBy问题

1
2
ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'xxx' which is not 
functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

解决办法一

  1. 查询 sql_mode

    1
    select @@global.sql_mode;

    结果如下

    1
    ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

    只需要将上面的 ONLY_FULL_GROUP_BY 去掉就行

    使用如下语句

    1
    set @@global.sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

    这种方法存在的问题

    1. 在有些时候不生效
    2. mysql重启之后配置失效

解决办法二

打开 mysql配置文件 my.cnf,在最下面添加

1
2
[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

使用这种方法会永久解决上面的报错问题

P.S. 如果 mysql 使用的是 docker

在进入容器内部

1
docker exec -it my-mysql /bin/bash

之后可能出现没有 vi/vim 工具导致无法修改配置文件

在此情况下首先执行

1
apt-get update

然后安装 vim

1
apt-get install vim