From 3a0965349340d4675592ec24a1805e9006ccf2e6 Mon Sep 17 00:00:00 2001
From: Bunny <1319900154@qq.com>
Date: Thu, 20 Feb 2025 19:05:29 +0800
Subject: [PATCH] =?UTF-8?q?SQL=E6=80=A7=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 5 +-
src/.vuepress/{docker => }/Dockerfile | 0
src/.vuepress/config.ts | 10 +-
src/.vuepress/{docker => }/nginx.conf | 0
src/.vuepress/theme.ts | 1 +
src/note/Base/CSS/01/01-media.md | 91 ++++++
src/note/Base/CSS/01/02-css-select.md | 155 +++++++++++
src/note/Base/CSS/01/README.md | 14 +
src/note/Base/CSS/README.md | 16 ++
src/note/Base/CSharp/README.md | 2 +-
src/note/Base/JavaScript/README.md | 2 +-
src/note/Base/README.md | 1 -
src/note/Base/设计模式.md | 2 +-
src/note/SQL/Optimize/1-11.md | 381 ++++++++++++++++++++++++++
src/note/SQL/Optimize/README.md | 14 +
15 files changed, 681 insertions(+), 13 deletions(-)
rename src/.vuepress/{docker => }/Dockerfile (100%)
rename src/.vuepress/{docker => }/nginx.conf (100%)
create mode 100644 src/note/Base/CSS/01/01-media.md
create mode 100644 src/note/Base/CSS/01/02-css-select.md
create mode 100644 src/note/Base/CSS/01/README.md
create mode 100644 src/note/Base/CSS/README.md
create mode 100644 src/note/SQL/Optimize/1-11.md
create mode 100644 src/note/SQL/Optimize/README.md
diff --git a/.gitignore b/.gitignore
index 411fb0d..5ea8f07 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
-
+.idea
+dist
node_modules/
src/.vuepress/.cache/
src/.vuepress/.temp/
-src/.vuepress/dist/
+src/.vuepress/docker/dist/
diff --git a/src/.vuepress/docker/Dockerfile b/src/.vuepress/Dockerfile
similarity index 100%
rename from src/.vuepress/docker/Dockerfile
rename to src/.vuepress/Dockerfile
diff --git a/src/.vuepress/config.ts b/src/.vuepress/config.ts
index 84733d0..3149051 100644
--- a/src/.vuepress/config.ts
+++ b/src/.vuepress/config.ts
@@ -1,19 +1,15 @@
import { defineUserConfig } from "vuepress";
-
+import { viteBundler } from "@vuepress/bundler-vite";
import theme from "./theme.js";
export default defineUserConfig({
+ bundler: viteBundler({}),
base: "/",
-
lang: "zh-CN",
title: "Bunny的博客",
description: "Bunny 博客 全栈开发",
- plugins: [
-
- ],
+ plugins: [],
theme,
-
// 和 PWA 一起启用
shouldPrefetch: true,
});
-
\ No newline at end of file
diff --git a/src/.vuepress/docker/nginx.conf b/src/.vuepress/nginx.conf
similarity index 100%
rename from src/.vuepress/docker/nginx.conf
rename to src/.vuepress/nginx.conf
diff --git a/src/.vuepress/theme.ts b/src/.vuepress/theme.ts
index 95b0acf..b53f695 100644
--- a/src/.vuepress/theme.ts
+++ b/src/.vuepress/theme.ts
@@ -94,6 +94,7 @@ export default hopeTheme(
markdown: {
align: true,
attrs: true,
+ alert: true,
codeTabs: true,
component: true,
demo: true,
diff --git a/src/note/Base/CSS/01/01-media.md b/src/note/Base/CSS/01/01-media.md
new file mode 100644
index 0000000..1312729
--- /dev/null
+++ b/src/note/Base/CSS/01/01-media.md
@@ -0,0 +1,91 @@
+---
+dir:
+ order: 1
+---
+
+# 引入CSS
+
+## 样式
+
+### 外部样式
+
+在link标记中rel和href属性是必须的,type属性和media属性可省略
+
+```html
+
+```
+
+### 多个样式
+
+```html
+
+
+```
+
+### 候选样式
+
+> [!warning]
+> 部分浏览器不支持候选样式(IE和firefox支持)
+
+如果需要在浏览器中进行候选样式表,需要在后面加上`title`
+
+```html
+
+```
+
+### 内部样式
+
+使用`style`元素,其中`style`可以写多个
+
+```html
+
+```
+
+使用`@import`指令
+
+> [!caution]
+>
+> `@import`必须出现在`style`元素中,且要放在其他CSS规则之前,否则将根本不起作用。
+
+```css
+
+```
+
+多个`@import`指令
+
+```css
+
+```
+
+### 行内样式
+
+> [!warning]
+>
+> 行间样式若存在多个style属性,**只能识别第一个**
+
+```html
+
+
+```
+
diff --git a/src/note/Base/CSS/01/02-css-select.md b/src/note/Base/CSS/01/02-css-select.md
new file mode 100644
index 0000000..86e8b31
--- /dev/null
+++ b/src/note/Base/CSS/01/02-css-select.md
@@ -0,0 +1,155 @@
+---
+dir:
+ order: 2
+---
+
+# CSS选择器
+
+## 选择器
+
+### 通配选择器
+
+```css
+*{color: red;}
+```
+
+### 元素选择器
+
+```css
+html {
+ color: black;
+}
+
+p {
+ color: gray;
+}
+
+h2 {
+ color: silver;
+}
+```
+
+### 类选择器
+
+```css
+.div {
+ color: red;
+}
+```
+
+### ID选择器
+
+```css
+#test {
+ color: red;
+}
+
+div#test {
+ color: red;
+}
+```
+
+### 属性选择器
+
+#### 简单属性选择器
+
+```css
+h1[class] {
+ color: red;
+}
+
+img[alt] {
+ color: red;
+}
+
+a[href][title] {
+ color: red;
+}
+
+#div[class] {
+ color: red;
+}
+
+.box[id] {
+ color: red;
+}
+
+[class] {
+ color: red;
+}
+```
+
+#### 具体属性选择器
+
+```css
+a[href="http://www.baidu.com"][title="baidu"] {
+ color: red;
+}
+
+[class="test box"] {
+ color: red;
+}
+
+[id="tox"] {
+ color: red;
+}
+```
+
+#### 部分属性选择器
+
+> [!info]
+>
+> 信息文字
+
+```css
+/* 选择class属性值在用空格分隔的词列表中包含词语"b" 的所有元素 */
+[class~="b"]
+```
+
+> ![!info]
+>
+> 选择class属性值等于b或以b-开头的所有元素
+
+```css
+[class |="b"] /* class="ab"不满足[class ~="b"],而class="a b"或class="b"满足 */
+[class ^="b"] 选择class属性值以"b"开头的所有元素
+[class $="b"] 选择class属性值以"b"结尾的所有元素
+[class *="b"] 选择class属性值包含"b"的所有元素
+```
+
+### 分组选择器
+
+```css
+h1,p{color: red;}
+```
+
+### 后代选择器
+
+```css
+ul li{color: red;}
+div p, ul li{color: red;}
+ul > li{color: red;}
+```
+
+### 兄弟元素选择器
+
+> [!warning]
+>
+> 相邻兄弟选择器(IE6-不支持)
+
+```css
+div + p{color: red;}
+```
+
+> [!warning]
+>
+> 两个元素之间的文本内容不会影响相邻兄弟结合符起作用
+>
+> 通用兄弟选择器(IE7-不支持)
+
+选择匹配的F元素,且位于匹配的E元素后的所有匹配的同级F元素
+
+```css
+div ~ p {color:red;}
+```
+
diff --git a/src/note/Base/CSS/01/README.md b/src/note/Base/CSS/01/README.md
new file mode 100644
index 0000000..65c8d0e
--- /dev/null
+++ b/src/note/Base/CSS/01/README.md
@@ -0,0 +1,14 @@
+---
+title: CSS和文档
+index: false
+icon: guidance:study-room
+headerDepth: 4
+category:
+ - 笔记
+ - 记录
+ - 学习
+ - 基础
+ - CSS
+---
+
+
\ No newline at end of file
diff --git a/src/note/Base/CSS/README.md b/src/note/Base/CSS/README.md
new file mode 100644
index 0000000..ecbcf60
--- /dev/null
+++ b/src/note/Base/CSS/README.md
@@ -0,0 +1,16 @@
+---
+title: CSS笔记
+index: false
+icon: vaadin:css
+headerDepth: 3
+category:
+ - 笔记
+ - 记录
+ - 学习
+ - 基础
+ - CSS
+dir:
+ order: 4
+---
+
+
\ No newline at end of file
diff --git a/src/note/Base/CSharp/README.md b/src/note/Base/CSharp/README.md
index 0eadf4d..1742dad 100644
--- a/src/note/Base/CSharp/README.md
+++ b/src/note/Base/CSharp/README.md
@@ -9,7 +9,7 @@ category:
- 学习
- 基础
dir:
- order: 1
+ order: 3
---
\ No newline at end of file
diff --git a/src/note/Base/JavaScript/README.md b/src/note/Base/JavaScript/README.md
index 12551bc..39abe47 100644
--- a/src/note/Base/JavaScript/README.md
+++ b/src/note/Base/JavaScript/README.md
@@ -2,7 +2,7 @@
title: JavaScript
index: true
icon: devicon:javascript
-headerDepth: 4
+headerDepth: 3
category:
- 笔记
- 记录
diff --git a/src/note/Base/README.md b/src/note/Base/README.md
index 9fcba55..a2c14e7 100644
--- a/src/note/Base/README.md
+++ b/src/note/Base/README.md
@@ -2,7 +2,6 @@
title: 基础笔记
index: false
icon: guidance:study-room
-headerDepth: 4
category:
- 笔记
- 记录
diff --git a/src/note/Base/设计模式.md b/src/note/Base/设计模式.md
index 4d13e81..ed0ef1c 100644
--- a/src/note/Base/设计模式.md
+++ b/src/note/Base/设计模式.md
@@ -1,6 +1,6 @@
---
dir:
- order: 4
+ order: 5
---
diff --git a/src/note/SQL/Optimize/1-11.md b/src/note/SQL/Optimize/1-11.md
new file mode 100644
index 0000000..73822fa
--- /dev/null
+++ b/src/note/SQL/Optimize/1-11.md
@@ -0,0 +1,381 @@
+---
+dir:
+ order: 11
+---
+
+# 使用高效查询
+
+## 参数是子查询
+
+### 使用 EXISTS 代替 IN
+
+一般来说,如果代码中用到了大量的 IN 谓词,只要对其优化,就能大幅度提升性能。
+
+在大多数时候,`[NOT] IN` 和`[NOT] EXISTS`返回结果是相同的,但是当它们用于子查询时,EXISTS 的速度回快一些。
+
+> [!tip]
+>
+> 如果连接列`id`上建立了索引,那么查询`class_b`时不用查询实际的表,只需要查询索引就可以了。
+>
+> 如果使用`EXISTS`,那么只要查到一行数据满足条件就会终止查询,不用像使用`IN`一样扫描全表。
+>
+> > [!important]
+> > 在这一点上和 `NOT EXISTS`是一样的。
+
+**慢查询**
+
+> [!tip]
+> 但是在可读性上`IN`要比`EXISTS`好
+
+```sql
+SELECT
+ *
+FROM
+ class_a
+WHERE
+ id IN ( SELECT id FROM class_b )
+```
+
+**快查询**
+
+> [!info]
+> 使用 IN 查询时,数据库首先会执行子查询,然后将结果存储在一张临时表里(内联视图),接着再扫描整个视图。在很多情况下,这种做法非常耗资源,而且工作表中通常没有索引。
+
+```sql
+SELECT
+ *
+FROM
+ class_a a
+WHERE
+ EXISTS ( SELECT * FROM class_b b WHERE a.id = b.id )
+```
+
+### 使用连接替代 IN
+
+还可以像下面这扁平化。
+
+> [!info]
+>
+> 这种写法至少可以用到一张表上的`id`列上的索引。而且,因为没有了子查询,所以数据库也不会生成中间表。
+>
+> 但是没有索引,那么和连接相比,可能`EXISTS`会略胜一筹。
+
+```sql
+SELECT
+ a.id,
+ a.NAME
+FROM
+ class_a a
+ INNER JOIN class_b b ON a.id = b.id
+```
+
+## 避免排序
+
+> [!caution]
+> 排序如果只在内存中进行,那么还好;如果内存不足需要在硬盘上排序,性能会急剧恶化。
+
+会排序的运算包含下面这些。
+
+- `GROUP BY`子句
+- `ORDER BY`子句
+- 聚合函数(`SUM`、`COUNT`、`AVG`、`MAX`、`MIN`)
+- `DISTINCT`
+- 集合运算符(`UNION`、`INTERSECT`、`EXCEPT`)
+- 窗口函数(`RANK`、`ROW_NUMBER`)
+
+### 灵活使用 ALL
+
+SQL 中有`UNION`、`INTERSECT`、`EXCEPT`三个集合运算符,在默认的使用方式下,这些运算符会为了排除重复数据进行排序。
+
+```sql
+SELECT * FROM class_a UNION SELECT * FROM class_b
+```
+
+如果不在乎结果中是否有重复数据,可以使用`UNION ALL`代替`UNION`。
+
+> [!warning]
+> 加上`ALL`可选项是优化性能的一个非常有效手段,但是各种 DBMS 对它实现情况参差不齐。
+
+```sql
+SELECT * FROM class_a UNION ALL SELECT * FROM class_b
+```
+
+### 使用 EXISTS 代替 DISTINCT
+
+为了排除重复数据,`DISTINCT`也会进行排序。可以考虑使用`EXISTS`,以避免排序。
+
+```sql
+SELECT DISTINCT
+ i.item_no
+FROM
+ items i
+ INNER JOIN saleshistory sh ON i.item_no = sh.item_no
+```
+
+最好办法是用`EXISTS`
+
+> [!tip]
+> 这样执行过程中不会排序,而且使用`EXISTS`和使用连接一样高效
+
+```sql
+SELECT
+ item_no
+FROM
+ items i
+WHERE
+ EXISTS ( SELECT * FROM saleshistory sh WHERE i.item_no = sh.item_no )
+```
+
+### 在极值函数中使用(MAX/MIN)
+
+如果参数字段上建有索引,则只需要扫描索引,不需要扫描整张表。
+
+**扫描整张表**
+
+```sql
+SELECT MAX(item) FROM items
+```
+
+**这样写可以用到索引**
+
+> [!tip]
+> 因为 item_no 是表 items 唯一索引,所以效果更好。
+
+```sql
+SELECT MAX(item_no) FROM items
+```
+
+### 能写在 WHERE 语句里就不要写 HAVING 里
+
+```sql
+SELECT
+ sale_date,
+ SUM( quantity )
+FROM
+ saleshistory
+GROUP BY
+ sale_date
+HAVING
+ sale_date = '2018-10-01'
+```
+
+**聚合前使用 WHERE 子句过滤**
+
+> [!important]
+> HAVING 子句是针对聚合后生成的视图进行筛选的,但是很多时候,聚合后的视图并没有继承原表的索引结构。
+
+```sql
+SELECT
+ sale_date,
+ SUM( quantity )
+FROM
+ saleshistory
+WHERE
+ sale_date = '2018-10-01'
+GROUP BY
+ sale_date
+```
+
+### 在 GROUP BY 子句和 ORDER BY 中使用索引
+
+一般来说,GROUP BY 子句和 RODER BY 子句都会进行排序,以对行进行排列和替换。不过,通过指定代索引的列作为 GROUP BY 和 ORDER BY 的列,可以实现高速查询。
+
+## 真的用到索引了吗
+
+### 在索引字段上进行运算
+
+```sql
+SELECT * FROM items WHERE col_1* 1.1 > 100
+```
+
+> [!tip]
+>
+> 人们普遍认为,SQL语言主要目的不是进行运算,但实际上,数据库大多连这种程度的转换也不会做。
+
+把运算符放到查询条件右侧,就可以用到索引了。
+
+```sql
+SELECT * FROM items WHERE col_1 > 100 / 1.1
+```
+
+同样,在查询条件的左侧使用函数时,也不会用到索引
+
+```sql
+SELECT * FROM items WHERE SUBSTR(col_1,1,1) = 'a'
+```
+
+> [!warning]
+>
+> 使用索引时,列应该是原始字段。
+
+### 索引字段存在NULL
+
+索引中的NULL不好处理,对此实现也各种不同。这是因为如果使用`IS NULL`和`IS NOT NULL`,索引就无法使用了,而且`NULL`很多字段也无法使用索引。
+
+```sql
+SELECT * FROM table WHERE col_1 IS NULL
+```
+
+如果需要使用`IS NOT NULL`的功能,又想用到索引,那么可以使用下面的方法。这里默认
+
+```sql
+SELECT * FROM table WHERE col_1 > 0
+```
+
+原理很简单,只要不使用不等号制定一个比最小值最还小的数,就可以选出`col_1`的值。因为`col_ > NULL`的执行结果是`unknown`,所以当col_1列的值为`NULL`的行不会被选择。
+
+### 使用否定形式
+
+- `<>`
+- `!=`
+- `NOT IN`
+
+> [!warning]
+>
+> 下面的SQL语句也不会用到索引。
+
+```sql
+SELECT * FROM table WHERE col_1 <> 100
+```
+
+### 使用OR
+
+在`col_1`和 `col_2`上分别建立了不同的索引,或者建立了`(col_1,col_2)`这样联合索引,如果使用`OR`连接条件,那么要么不会用到索引,要么用到了,但是效率比`AND`要差很多。
+
+> [!important]
+>
+> 如果无论如何都要使用OR,那么有一个办法是使用位图索引。但是如果使用这种索引,更新数据的性能开销会很大,而且索引本身用途也存在限制(通常用于在线更新处理较少的`BI/DWH`系统
+
+```sql
+SELECT * FROM table WHERE col_1 > 100 OR col_2 = 'abc'
+```
+
+### 使用联合索引,列的顺序错误
+
+假设存在一个顺序是`col_1,col_2,col_3`的联合索引。设置条件索引顺序很重要。
+
+> [!important]
+>
+> 联合索引中第一列(col_1)必须写在查询条件的开头,而且索引中列的顺序不能颠倒。有些数据库颠倒后也能使用索引,但是性能还是比顺序正确时差一些。
+>
+> 如果无法保证查询条件里的列顺序与索引一致,可以考虑将联合索引拆分为多个索引。
+
+> [!tip]
+>
+> 如:Oracle,即使改变索引顺序,也可以通过SKIP SCAN的形式来使用索引,但是效率要比正常扫描索引时低。
+
+```sql
+○ SELECT * FROM table WHERE col_1 = 10 AND col_2 = 100 AND col_3 = 500
+○ SELECT * FROM table WHERE col_1 = 10 AND col_2 = 100
+× SELECT * FROM table WHERE col_1 = 10 AND col_3 = 500
+× SELECT * FROM table WHERE col_2 = 100 AND col_3 = 500
+```
+
+### 使用LIKE谓词
+
+> [!important]
+>
+> 使用LIKE谓词进行后方一致或中间一致的匹配。只有前方一致的匹配才能用到索引。
+
+```sql
+× SELECT * FROM table WHERE col_1 LIKE '%a'
+× SELECT * FROM table WHERE col_1 LIKE '%a%'
+○ SELECT * FROM table WHERE col_1 LIKE 'a%'
+```
+
+### 进行默认的类型转换
+
+下面是对字符串类型的`col_1`列指定条件的实例。
+
+> [!tip]
+>
+> 默认类型转换不仅会增加额外性能开销,还会导致索引不可用,可以说是百害而无一利。虽然这有些还不至于出错,但还是不要嫌麻烦,在需要类型转换时显示斤西瓜类型转换。
+
+>[!info]
+>
+>别忘了转换要写在一边,而不是另一边。
+>
+>在有些DBMS(如PostgreSQL)中,数据类型写在表达式的不同侧就会发生错误,显式进行类型转换还有利于我们在开发时注意避免编写性能低下查询。
+
+```sql
+× SELECT * FROM table WHERE col_1 = 10
+× SELECT * FROM table WHERE col_1 = '10'
+○ SELECT * FROM table WHERE col_1 = CAST(10, AS CHAR(2))
+```
+
+## 减少中间表
+
+频繁使用中间表会带来两个问题:一是展开数据需要耗费内存(或存储器)资源,二是原始表中的索引不容易被用到(特别是聚合时)。因此,尽量减少中间表的使用也是一个提升性能的重要方法。
+
+### 灵活使用HAVING子句
+
+对聚合结果指定筛选条件时,使用HAVING子句是基本原则。不习惯使用HAVING 子句的数据库工程师可能会倾向于像下面这样先生成一张中间表,然后在 WHERE 子句中指定筛选条件。
+
+```sql
+SELECT
+ *
+FROM
+ ( SELECT sale_date, MAX( quantity ) AS max_qty FROM saleshistory GROUP BY sale_date ) WHBRE max_qty >= 10;
+```
+
+**优化后**
+
+HAVING 子句和聚合操作是同时执行的,所以比起先生成中间表,然后再执行的 WHERE 子句,效率会更高一些,而且代码看起来也更简洁。
+
+```sql
+SELECT
+ sale_date,
+ MAX( quantity )
+FROM
+ saleshistory
+GROUP BY
+ sale_date
+HAVING
+ MAX( quantity ) >= 10;
+```
+
+### 需要对多个字段使用 IN 谓词时,先将它们汇总到一处
+
+SQL-92 中加入了行与行比较的功能。这样一来,比较谓词`=、<、>`和 IN 谓词的参数就不能是标量值,而应是值列表了。我们来看看下面这道例题。这里对多个字段使用了`IN` 谓词,id 列是主键。
+
+```sql
+SELECT
+ id,
+ state,
+ city
+FROM
+ Addressesl A1
+WHERE
+ state IN ( SELECT state FROM Addresses2 A2 WHERE A1.id = A2.id )
+ AND city IN ( SELECT ity FROM Addresses2 A2 WHERE A1.id = A2.id );
+```
+
+这段代码中用到了两个子查询。但是,如果像下面这样把字段连接在起,就能把逻辑写在一处了。
+
+```sql
+SELECT
+ *
+FROM
+ Addressesl A1
+WHERE
+ id || state || city IN ( SELECT id || statel || city )
+FROM
+ Addresses2 A2
+ );
+```
+
+### 先进行连接再进行聚合
+
+连接和聚合同时使用时,先进行连接操作可以避免产生中间表。原因是,从集合运算的角度来看,连接做的是“乘法运算”连接表双方是一对一、一对多的关系时,连接运算后数据的行数不会增加。而且,因为在很多设计中多对多的关系可以分解成两个一对多的关系,所以这个技巧可以应用在大部分情况中。
+
+### 合理地使用视图
+
+> [!warning]
+>
+> 一般来说,我们需要格外注意,避免在视图中进行聚合操作。
+
+视图是非常方便的工具,相信有很多人会在日常工作中频繁地使用它。但是,如果没有经过深入思考就定义复杂的视图,可能会带来巨大的性能问题。特别是当视图的定义语句中包含以下运算时,SQL会非常低效,执行速度也会变得非常慢。
+
+- 聚合函数(`AVG、COUNT、SUM、MIN、MAX`)
+- 集合运算符(`UNION、INTERSECT、EXCEPT`等)
+
diff --git a/src/note/SQL/Optimize/README.md b/src/note/SQL/Optimize/README.md
new file mode 100644
index 0000000..206e787
--- /dev/null
+++ b/src/note/SQL/Optimize/README.md
@@ -0,0 +1,14 @@
+---
+title: SQL进阶
+index: true
+icon: ph:file-sql-light
+headerDepth: 4
+category:
+ - 笔记
+ - 记录
+ - 学习
+ - 问题
+ - SQL
+---
+
+