一、【多选】下列关于Join 运算不正确的是:
a. Nested Loop Join 不能使用索引做优化。
b. 如果左表太大,不能放入内存中,则不能使用 Hash Join。
c. 如果 Join 的一个输入表在 Join Key 上有序,则一定会使用 Sort Merge Join。
d. Broadcast Join 适用于一张表很小,另一张表很大的场景。
a选项:Nested Loop Join可以使用索引优化。
b选项:可以先分区,再连接
c选项:还可以使用hash join
Sql Server支持三种物理连接:nested loops join(嵌套连接),merge join和hash join.
nested loops join(NLJ)
NLJ是通过两层循环,用第一张表做Outter Loop,第二张表做Inner Loop,Outter Loop的每一条记录跟Inner Loop的记录作比较,符合条件的就输出。 有三种算法:
- Simple Nested Loop Join(SNLJ)算法
SNLJ就是两层循环全量扫描连接的两张表,得到符合条件的两条记录则输出,这也就是让两张表做笛卡尔积,比较次数是R * S,是比较暴力的算法,会比较耗时。
- Index Nested Loop Join(INLJ)算法
INLJ是在SNLJ的基础上做了优化,通过连接条件确定可用的索引,在Inner Loop中扫描索引而不去扫描数据本身,从而提高Inner Loop的效率。 而INLJ也有缺点,就是如果扫描的索引是非聚簇索引,并且需要访问非索引的数据,会产生一个回表读取数据的操作,这就多了一次随机的I/O操作。
- Block Nested Loop Join(BNLJ)算法
BNLJ在SNLJ的基础上使用了join buffer,会提前读取Inner Loop所需要的记录到buffer中,以提高Inner Loop的效率。
merge join
Merge join 合并连接。两个集合进行merge join,需要有一个等值的条件,然后需要两个已排序好的集合。
Merge join的操作通常分三步:
1. 对连接的每个表做table access full;
2. 对table access full的结果进行排序。
3. 进行merge join对排序结果进行合并。
在全表扫描比索引范围扫描再进行表访问更可取的情况下,Merge Join会比Nested Loop性能更佳。 Merge Join可适于于非等值Join(>,<,>=,<=,但是不包含!=,也即<>)
hash join
Hash Join是做大数据集连接时的常用方式,优化器使用两个表中较小(相对较小)的表利用Join Key在内存中建立散列表,然后扫描较大的表并探测散列表,找出与Hash表匹配的行。
Hash Join只能应用于等值连接
| 类别 | Nested Loop | Hash Join | Merge Join |
|---|---|---|---|
| 使用条件 | 任何条件 | 等值连接(=) | 等值或非等值连接(>,<,=,>=,<=),‘<>’除外 |
| 相关资源 | CPU、磁盘I/O | 内存、临时空间 | 内存、临时空间 |
| 特点 | 当有高选择性索引或进行限制性搜索时效率比较高,能够快速返回第一次的搜索结果。 | 当缺乏索引或者索引条件模糊时,Hash Join比Nested Loop有效。通常比Merge Join快。在数据仓库环境下,如果表的纪录数多,效率高。 | 当缺乏索引或者索引条件模糊时,Merge Join比Nested Loop有效。非等值连接时,Merge Join比Hash Join更有效 |
| 缺点 | 当索引丢失或者查询条件限制不够时,效率很低;当表的纪录数多时,效率低。 | 为建立哈希表,需要大量内存。第一次的结果返回较慢。 | 所有的表都需要排序。它为最优化的吞吐量而设计,并且在结果没有全部找到前不返回数据。 |
二、给定一个正整数数组 arrs 和整数 K ,请找出该数组内乘积小于等于 k 的连续的子数组的个数,算法时间复杂度o(n)。
java
class Solution {
public int numSubarrayProductLessThanK(int[] arrs, int k) {
// 特殊值判断
if (k <= 1) return 0;
// 定义所需变量
int res = 0;
int left = 0;
int right = 0;
int fac = 1;
// 遍历
while (right < arrs.length) {
fac *= arrs[right];
// 滑动
while (left <= right && fac >= k) {
fac /= arrs[left];
left++;
}
res += right - left + 1;
right++;
}
// 返回结果
return res;
}
}
go
func numSubarrayProductLessThanK(arrs []int, k int) int {
//start: 10:28,... end 11.23
//思路1: 滑动窗口
//参数处理
if len(arrs) == 0 || k <= 0 {
return 0
}
//滑动窗口
res := 0
left,right,product := 0,0,1
for ;right < len(arrs);right++ {
product *= arrs[right]
for left <= right && product >= k {
product /= arrs[left]
left ++
}
if left <= right {
res += right-left +1
}
}
return res
}