MySQL 索引有眼些

  • B+树索引:所有数据存储在叶子节点,复杂度为O(logn),适合范围查询。
  • 哈希索引: 适合等值查询,检索效率高,一次到位。
  • 全文索引:MyISAM和InnoDB中都支持使用全文索引,一般在文本类型char,text,varchar类型上创建。
  • R-Tree索引: 用来对GIS数据类型创建SPATIAL索引
  • 物理存储维度
  • 聚集索引:聚集索引就是以主键创建的索引,在叶子节点存储的是表中的数据。(Innodb存储引擎)
  • 非聚集索引:非聚集索引就是以非主键创建的索引,在叶子节点存储的是主键和索引列。(Innodb存储引擎)
  • 主键索引:一种特殊的唯一索引,不允许有空值。
  • 普通索引:MySQL中基本索引类型,允许空值和重复值。
  • 联合索引:多个字段创建的索引,使用时遵循最左前缀原则。
  • 唯一索引:索引列中的值必须是唯一的,但是允许为空值。
  • 空间索引:MySQL5.7之后支持空间索引,在空间索引这方面遵循OpenGIS几何数据模型规则。

MySQL 索引使用有哪些注展事项

  • 对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引,同时索引要满足 最左匹配。
  • 应尽量避免在 where 子句中对字段进行 null 值判断, 并字段为null值的尽量避免建立索引
  • 如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。
  • 应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。
  • 索引并不是越多越好,索引固然可 以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑。

大数据下的查询优化

看数据量级的规模,考虑是否分库分表,并进行热数据的缓存例如redis等等技术,冷数据做好拆分数据库及分布式架构的布局

Spring 事务在哪几种情况下会失效

  • 方法用final修饰
  • 直接调用内部方法
  • 未被Spring管理
  • 多线程调用

LinkedHashMap 与HashMap 的区别 这个有点意思后续再看还有一个ConcurrentHashMap

HashMap 以一种无序的方式存储键值对。它通过 hashCode() 方法来计算元素的哈希值,并将元素插入到对应的桶中。当需要查找元素时,只需要通过 HashMap 的 get() 方法根据键获取对应的值即可。由于 HashMap 具有快速的插入和查找性能,因此它是最常用的 Map 实现类之一。

而 LinkedHashMap 则以插入顺序(或者访问顺序)存储键值对,即在插入元素时,每个元素都会按照插入的顺序被放置到链表的末尾。这使得当需要迭代 Map 元素时,可以按照插入顺序或访问顺序进行处理。在性能上,由于 LinkedHashMap 需要维护插入顺序,因此比 HashMap 稍微慢一些,但是这种性能损失通常是可以接受的。因此,当需要按照插入顺序遍历 Map 元素时,建议使用 LinkedHashMap。当不需要考虑遍历顺序时,HashMap 更加合适。

高并发下如何保证数据的唯一性?

增加数据表唯一性约束是最简单的方式,只需要在我们需要的字段中增加唯一约束,当插入相同数据时,数据库会验证数据唯一,当存在相同主键时,数据库会抛出异常信息。
使用同步(synchronous)
程序保存代码块中增加并发同步控制,该方法可以防止并发执行,单程序效率会降低。但实际上synchronous 避免不了数据的唯一性问题, 先做记录

给你一个 m 行 n列的矩阵 matrix,请按照 顺时针嫁旋顺序 ,返回矩阵中的所有元素

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//思路1————螺旋遍历
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
//矩阵 matrix 是 m 行 n 列的
int m = matrix.length;
int n = matrix[0].length;
//定义 res,用于保存结果
List<Integer> res = new ArrayList<Integer>();
//visited[i][j] == true 表示已经访问过矩阵中的元素 matrix[i][j]
boolean[][] visited = new boolean[m][n];
//direction = 1、2、3、4 时分别表示在矩阵中向右、下、左、上遍历
/*
初始时:
若 n == 1,则说明矩阵只有一列,此时只能向下开始遍历
若 n != 1,则说明矩阵有多列,此时可以按照向右→向下→向左→向上→向右→向下→...的方向开始遍历,直到将整个矩阵访问完为止
*/
int direction = (n == 1) ? 2 : 1;
//定义遍历起点的横纵坐标
int i = 0, j = 0;
//将遍历的起点 matrix[i][j] 添加到 res 中
res.add(matrix[i][j]);
//将遍历的起点设置为已访问的状态
visited[i][j] = true;
while (true) {
if (direction == 1 && j + 1 < n && visited[i][j + 1] == false) {
//向右遍历
while (j + 1 < n && visited[i][j + 1] == false) {
res.add(matrix[i][j + 1]);
visited[i][j + 1] = true;
j++;
}
direction++;
} else if (direction == 2 && i + 1 < m && visited[i + 1][j] == false) {
//向下遍历
while (i + 1 < m && visited[i + 1][j] == false) {
res.add(matrix[i + 1][j]);
visited[i + 1][j] = true;
i++;
}
direction++;
} else if (direction == 3 && j - 1 >= 0 && visited[i][j - 1] == false) {
//向左遍历
while (j - 1 >= 0 && visited[i][j - 1] == false) {
res.add(matrix[i][j - 1]);
visited[i][j - 1] = true;
j--;
}
direction++;
} else if (direction == 4 && i - 1 >= 0 && visited[i - 1][j] == false) {
//向上遍历
while (i - 1 >= 0 && visited[i - 1][j] == false) {
res.add(matrix[i - 1][j]);
visited[i - 1][j] = true;
i--;
}
direction = 1;
} else {
//遍历结束
break;
}
}
return res;
}
}

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
//思路2————旋转遍历
class Solution {
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> res = new ArrayList<>();
while (matrix.length >= 1) {
//遍历当前 matrix 的第一行
for (int num : matrix[0]) {
res.add(num);
}
//删除 matrix 的第一行,再将其逆时针旋转 90° 后并返回
matrix = DelRotateMatrix(matrix);
}
return res;
}

private int[][] DelRotateMatrix(int[][] matrix) {
//每次处理列数不变
int m = matrix[0].length;
//每次处理行数少一行
int n = matrix.length - 1;
int[][] newMatrix = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
newMatrix[i][j] = matrix[j + 1][m - i - 1];
}
}
return newMatrix;
}
}