在win11系统下的用户目录C:\Users\Choba下创建.wslconfig文件,写入如下内容[wsl2] networkingMode=mirrored保存后重启电脑
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? (Details: [13] 权限不够)
这个 "权限不够" 错误表明您的用户账户没有访问 Docker 守护进程所需的权限。以下是完整的解决方案：永久解决方案：将用户加入 docker 组1. 将您的用户添加到 docker 用户组sudo usermod -aG docker $USER2. 刷新当前用户组设置（不需要注销）newgrp docker3. 验证权限docker ps # 应能正常执行不报错临时解决方案：更改 Docker socket 权限（不推荐）临时更改权限（重启后失效）sudo chmod 666 /var/run/docker.sock永久更改权限（安全风险）sudo chmod a+rw /var/run/docker.sock
在Deepin系统中为AppImage应用添加图标并集成到应用程序菜单
1. 准备图标文件下载或创建.png图标（推荐尺寸 512x512 或 256x256），例如：wget -O ~/.local/share/icons/myapp.png https://example.com/icon.png或从AppImage自身提取图标：./YourApp.AppImage --appimage-extract # 解压后从squashfs-root目录获取图标2. 创建.desktop桌面文件在 ~/.local/share/applications/ 目录下创建文件（例如 myapp.desktop）：nano ~/.local/share/applications/myapp.desktop填入以下内容（根据实际情况修改路径和名称）：[Desktop Entry] Version=1.0 Type=Application Name=Navicat-Lite Exec=/home/choba/opt/AppImage/navicat17-premium-lite/navicat17-premium-lite-cs-x86_64.AppImage Icon=/home/choba/opt/AppImage/navicat17-premium-lite/logo.png Categories=Utility;Development; Terminal=false StartupNotify=true3. 赋予AppImage执行权限chmod +x /path/to/YourApp.AppImage4. 刷新桌面数据库update-desktop-database ~/.local/share/applications/5. 验证效果在Deepin启动器中搜索应用名称或直接启动测试：gtk-launch myapp注意事项图标路径问题如果图标未显示，尝试使用绝对路径（如 Icon=/home/user/.local/share/icons/myapp.png）或将图标复制到系统目录：/usr/share/pixmaps/多用户共享应用 将.desktop和图标放到系统目录：sudo mv myapp.desktop /usr/share/applications/ sudo mv myapp.png /usr/share/icons/AppImage兼容性 某些AppImage可能需要--no-sandbox等参数，在Exec行添加：Exec=/path/to/app --no-sandbox %U
在Linux系统中使用alist和rclone将云盘挂载在本地系统
引言随着云存储服务的普及，用户常常需要同时管理多个云盘（如阿里云盘、Google Drive、OneDrive 等）。如果能够将这些云存储统一挂载到本地文件系统，就能像操作本地文件一样直接访问云端数据，极大地提升效率。本文将通过 AList 和 Rclone 工具，手把手教你实现这一目标。一、工具简介1. AList 是什么？AList官网AList 是一个开源的 多存储文件列表程序，支持 20+ 种云存储服务，可以将不同云盘整合到统一的 Web 界面中，并通过 WebDAV 协议暴露接口。2. Rclone 是什么？Rclone官网Rclone 是一个命令行工具，专为云存储设计，支持 挂载、同步、加密 等功能，能够将远程存储挂载为本地磁盘。二、准备工作Linux 发行版（如 Ubuntu/CentOS）已安装 Docker 和 Docker Compose（用于运行 AList）,这里使用docker,避免环境依赖版本问题。终端操作权限三、部署 AList 服务1. 使用 Docker Compose 安装 AList创建alist目录：mkdir -p /home/choba/alist && cd /etc/alist mkdir data nano docker-compose.yml粘贴以下内容：services: alist: image: xhofe/alist:latest container_name: alist volumes: - './data:/opt/alist/data' ports: - '5244:5244' environment: - PUID=0 - PGID=0 - UMASK=022 - TZ=Asia/Shanghai # 设置时区（可选） restart: unless-stopped启动容器：docker compose up -d2. 获取管理员密码v3.25.0 及以上版本随机生成密码：docker exec -it alist ./alist admin random手动设置密码（替换 NEW_PASSWORD）：docker exec -it alist ./alist admin set NEW_PASSWORDv3.25.0 以下版本docker exec -it alist ./alist admin3. 配置云存储访问 http://服务器IP:5244/@login，使用管理员账号登录。进入 「存储」 → 「添加」 ，选择云盘类型（如阿里云盘），填写 Token 或 OAuth 配置。保存后，AList 会通过 WebDAV 协议暴露存储路径（如 http://IP:5244/dav）。四、使用 Rclone 挂载到本地1. 安装 Rclone# 一键安装脚本 curl https://rclone.org/install.sh | sudo bash # 或者使用apt安装 sudo apt install rclone2. 配置 Rclone 连接 AList 的 WebDAV╭─    ~/rclone-v1.69.1-linux-amd64 ··············································· ✔  at 17:06:19  ─╮ ╰─ rclone config ─╯ <5>NOTICE: Config file "/home/choba/.config/rclone/rclone.conf" not found - using defaults No remotes found, make a new one? n) New remote s) Set configuration password q) Quit config n/s/q> n Enter name for new remote. name> remote Option Storage. Type of storage to configure. Choose a number from below, or type in your own value. 1 / 1Fichier \ (fichier) 2 / Akamai NetStorage \ (netstorage) 3 / Alias for an existing remote \ (alias) 4 / Amazon Drive \ (amazon cloud drive) 5 / Amazon S3 Compliant Storage Providers including AWS, Alibaba, Ceph, China Mobile, Cloudflare, ArvanCloud, Digital Ocean, Dreamhost, Huawei OBS, IBM COS, IDrive e2, IONOS Cloud, Lyve Cloud, Minio, Netease, RackCorp, Scaleway, SeaweedFS, StackPath, Storj, Tencent COS, Qiniu and Wasabi \ (s3) 6 / Backblaze B2 \ (b2) 7 / Better checksums for other remotes \ (hasher) 8 / Box \ (box) 9 / Cache a remote \ (cache) 10 / Citrix Sharefile \ (sharefile) 11 / Combine several remotes into one \ (combine) 12 / Compress a remote \ (compress) 13 / Dropbox \ (dropbox) 14 / Encrypt/Decrypt a remote \ (crypt) 15 / Enterprise File Fabric \ (filefabric) 16 / FTP \ (ftp) 17 / Google Cloud Storage (this is not Google Drive) \ (google cloud storage) 18 / Google Drive \ (drive) 19 / Google Photos \ (google photos) 20 / HTTP \ (http) 21 / Hadoop distributed file system \ (hdfs) 22 / HiDrive \ (hidrive) 23 / In memory object storage system. \ (memory) 24 / Internet Archive \ (internetarchive) 25 / Jottacloud \ (jottacloud) 26 / Koofr, Digi Storage and other Koofr-compatible storage providers \ (koofr) 27 / Local Disk \ (local) 28 / Mail.ru Cloud \ (mailru) 29 / Microsoft Azure Blob Storage \ (azureblob) 30 / Microsoft OneDrive \ (onedrive) 31 / OpenDrive \ (opendrive) 32 / OpenStack Swift (Rackspace Cloud Files, Memset Memstore, OVH) \ (swift) 33 / Pcloud \ (pcloud) 34 / Put.io \ (putio) 35 / SMB / CIFS \ (smb) 36 / SSH/SFTP \ (sftp) 37 / Sia Decentralized Cloud \ (sia) 38 / Sugarsync \ (sugarsync) 39 / Transparently chunk/split large files \ (chunker) 40 / Union merges the contents of several upstream fs \ (union) 41 / Uptobox \ (uptobox) 42 / WebDAV \ (webdav) 43 / Yandex Disk \ (yandex) 44 / Zoho \ (zoho) 45 / premiumize.me \ (premiumizeme) 46 / seafile \ (seafile) Storage> webdav Option url. URL of http host to connect to. E.g. https://example.com. Enter a value. url> http://192.168.0.196:5244/dav Option vendor. Name of the WebDAV site/service/software you are using. Choose a number from below, or type in your own value. Press Enter to leave empty. 1 / Nextcloud \ (nextcloud) 2 / Owncloud \ (owncloud) 3 / Sharepoint Online, authenticated by Microsoft account \ (sharepoint) 4 / Sharepoint with NTLM authentication, usually self-hosted or on-premises \ (sharepoint-ntlm) 5 / Other site/service or software \ (other) vendor> 5 Option user. User name. In case NTLM authentication is used, the username should be in the format 'Domain\User'. Enter a value. Press Enter to leave empty. user> admin Option pass. Password. Choose an alternative below. Press Enter for the default (n). y) Yes, type in my own password g) Generate random password n) No, leave this optional password blank (default) y/g/n> y Enter the password: password: Confirm the password: password: Option bearer_token. Bearer token instead of user/pass (e.g. a Macaroon). Enter a value. Press Enter to leave empty. bearer_token> Edit advanced config? y) Yes n) No (default) y/n> n Configuration complete. Options: - type: webdav - url: http://192.168.0.196:5244/dav - vendor: other - user: admin - pass: *** ENCRYPTED *** Keep this "remote" remote? y) Yes this is OK (default) e) Edit this remote d) Delete this remote y/e/d> y按提示操作：选择 n（新建存储）类型选 webdav名称填 remote（可自定义）URL 填 http://IP:5244/dav用户名/密码填 AList 的管理员账号3. 挂载云盘到本地目录rclone mount remote:/Quark /home/choba/alist_mount \ --copy-links \ # 解析符号链接 --no-gzip-encoding \ # 禁用 GZIP 压缩 --no-check-certificate \ # 跳过 SSL 验证（不安全！） --allow-non-empty \ # 允许非空目录挂载 --umask 000 \ # 开放所有权限 --use-mmap # 内存映射优化核心参数解析参数作用说明适用场景注意事项remote:/Quark指定远程存储的路径：- remote: 预先配置的云存储名称（如 Alist、Google Drive 等）- /Quark: 远程存储中的目录名需要挂载特定目录而非根目录时使用确保 remote 已通过 rclone config 正确配置/home/choba/alist_mount本地挂载点路径将远程存储映射到本地文件系统需提前创建目录并确保有写入权限--copy-links解析符号链接为实际文件：- 若远程存在软链接，直接复制其指向的真实文件需要避免挂载时因符号链接导致路径无效可能增加首次挂载耗时--no-gzip-encoding禁用 HTTP 传输时的 GZIP 压缩：- 强制以原始格式传输数据服务器不支持压缩或传输已压缩文件（如视频）时可能略微增加带宽占用--no-check-certificate跳过 SSL/TLS 证书验证：- 允许使用自签名证书或忽略证书错误测试环境或内网中使用自签名证书时存在中间人攻击风险，生产环境慎用--allow-non-empty允许挂载到非空目录：- 默认情况下 rclone 禁止挂载到非空目录挂载目录已存在其他文件需保留时需确保目录内文件不会被覆盖--umask 000设置文件权限掩码：- 000 表示所有用户（所有者、组、其他）拥有读写执行权限（777）需要完全开放挂载目录权限时安全性较低，建议改为 022 （755 权限）--use-mmap启用内存映射（Memory Mapping）优化：- 利用系统内存加速大文件读写处理大文件（如视频编辑、数据库文件）时可能增加内存占用，需系统支持4. 验证挂载# 查看挂载点内容 ls ~/alist_mount若成功，会显示 AList 中配置的所有云盘目录。五、实现开机自动挂载1. 创建 systemd 服务文件sudo nano /etc/systemd/system/rclone-remote.service内容如下：[Unit] Description=rclone [Service] User=choba ExecStart=/usr/bin/rclone mount remote:/Quark /home/choba/alist_mount --copy-links --no-gzip-encoding --no-check-certificate --allow-non-empty --umask 000 --use-mmap [Install] WantedBy=multi-user.target 注：这里只使用choba账户，如果需要所有账户都能使用# 允许其他用户访问（Linux 需配置 /etc/fuse.conf） --allow-other \Linux 系统需允许用户挂载 FUSE：# 编辑 /etc/fuse.conf sudo nano /etc/fuse.conf取消注释：user_allow_other保存后重新登录用户。2. 启用并启动服务sudo systemctl daemon-reload sudo systemctl enable rclone-remote sudo systemctl start rclone-remote
问题:想搭建一个本地的接口文档服务器，在局域网内使用，使用的是wsl2+docker，搭建完成后可以使用localhost:端口号访问，但是不能通过本机ip进行访问。找了很多文档，修改防火墙规则，更改桥接模式，关闭虚拟机防火墙等等，都不行。 按官方文档说最新的wsl2是支持镜像模式的，wsl2和宿主机ip是一致的，可以直接进行访问，但是不行，后面试了很多方法，发现是因为使用1pan的时候将docker的iptables设置为true了。解决方法编辑/etc/docker/daemon.json文件添加如下内容{ "iptables": false }开放防火墙 管理员权限打开PowerShell运行# 可以通过这个命令获取40E0AC32-46A5-438A-A0B2-2B479E8F2E90 Get-NetFirewallHyperVVMSetting | Format-Table Name, Id -AutoSize Set-NetFirewallHyperVVMSetting -Name ‘{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}’ -DefaultInboundAction Allow3.编辑wslconfig开启镜像网络 wsl-configwin + r 输入 %UserProfile% 新建 .wslconfig 建议内容如下[wsl2] memory=8GB #内存最大值 swap=8GB #虚拟内存最大值 processors=4 #cpu核最大值 networkingMode=mirrored # 开启镜像网络 dnsTunneling=true # 开启 DNS Tunneling firewall=true # 开启 Windows 防火墙 autoProxy=true # 开启自动同步代理 [experimental] sparseVhd=true # 开启自动释放 WSL2 虚拟硬盘空间 autoMemoryReclaim=gradual # 开启自动回收内存 hostAddressLoopback=true # 允许容器通过分配给主机的 IP 地址连接到主机重启wsl就可通过宿主机ip进行访问。
1. 数据库事务概述1.1 存储引擎支持情况SHOW ENGINES 命令来查看当前 MySQL 支持的存储引擎都有哪些，以及这些存储引擎是否支持事务。 能看出在 MySQL 中，只有InnoDB 是支持事务的。1.2 基本概念事务：一组逻辑操作单元，使数据从一种状态变换到另一种状态。 事务处理的原则：保证所有事务都作为 一个工作单元 来执行，即使出现了故障，都不能改变这种执行方 式。当在一个事务中执行多个操作时，要么所有的事务都被提交( 存下来；要么数据库管理系统将 放弃 所作的所有 commit )，那么这些修改就 永久 地保 修改 ，整个事务回滚( rollback )到最初状态。# 案例：AA用户给BB用户转账100 update account set money = money - 100 where name = 'AA'; # 服务器宕机 update account set money = money + 100 where name = 'BB';1.3 事务的ACID特性原子性（atomicity）：原子性是指事务是一个不可分割的工作单位，要么全部提交，要么全部失败回滚。一致性（consistency）： 一致性是指事务执行前后，数据从一个 合法性状态 变换到另外一个 合法性状态 。这种状态 是 语义上 的而不是语法上的，跟具体的业务有关。隔离型（isolation）： 事务的隔离性是指一个事务的执行 不能被其他事务干扰，即一个事务内部的操作及使用的数据对 并发 的其他事务是隔离的，并发执行的各个事务之间不能相互干扰。 持久性（durability）： 持久性是指一个事务一旦被提交，它对数据库中数据的改变就是 永久性的 ，接下来的其他操作和数据库 故障不应该对其有任何影响。 持久性是通过 事务日志 来保证的。日志包括了 重做日志 和 回滚日志 。当我们通过事务对数据进行修 改 的时候，首先会将数据库的变化信息记录到重做日志中，然后再对数据库中对应的行进行修改。这样 做 的好处是，即使数据库系统崩溃，数据库重启后也能找到没有更新到数据库系统中的重做日志，重新 执 行，从而使事务具有持久性。总结：ACID是事务的四大特征，在这四个特性中，原子性是基础，隔离性是手段，一致性是约束条件， 而持久性是我们的目的。 数据库事务，其实就是数据库设计者为了方便起见，把需要保证 原子性、 隔离性、 一致性 和 持久性 的一个或多个数据库操作称为一个事务1.4 事务的状态我们现在知道 事务 是一个抽象的概念，它其实对应着一个或多个数据库操作，MySQL根据这些操作所 执 行的不同阶段把 事务 大致划分成几个状态：活动的（active） 事务对应的数据库操作正在执行过程中时，我们就说该事务处在部分提交的（partially committed） 当事务中的最后一个操作执行完成，但由于操作都在内存中执行，所造成的影响并 没有刷新到磁盘 时，我们就说该事务处在 部分提交的 状态。失败的（failed） 当事务处在 活动的 或者 部分提交的 状态时，可能遇到了某些错误（数据库自身的错误、操作系统 错误或者直接断电等）而无法继续执行，或者人为的停止当前事务的执行，我们就说该事务处在 失 败的 状态。中止的（aborted） 如果事务执行了一部分而变为 失败的 状态，那么就需要把已经修改的事务中的操作还原到事务执 行前的状态。换句话说，就是要撤销失败事务对当前数据库造成的影响。我们把这个撤销的过程称 之为 回滚 。当 回滚 操作执行完毕时，也就是数据库恢复到了执行事务之前的状态，我们就说该 事 务处在了 中止的 状态。 举例：UPDATE accounts SET money = money - 50 WHERE NAME = 'AA'; UPDATE accounts SET money = money + 50 WHERE NAME = 'BB';提交的（committed）当一个处在 部分提交的 状态的事务将修改过的数据都 在了 提交的 状态。 一个基本的状态转换图如下所示： 图中可见，只有当事务处于 提交的或者 中止的状态时，一个事务的生命周期才算是结束了。对于 已经提交的事务来说，该事务对数据库所做的修改将永久生效，对于处于中止状态的事务，该事务 对数据库所做的所有修改都会被回滚到没执行该事务之前的状态。2. 如何使用事务使用事务有两种方式，分别为 显式事务 和 隐式事务 。2.1 显式事务步骤1： START TRANSACTION 或者 BEGIN ，作用是显式开启一个事务。mysql> BEGIN; #或者 mysql> START TRANSACTION;START TRANSACTION 语句相较于 BEGIN 特别之处在于，后边能跟随几个 修饰符 :① READ ONLY ：标识当前事务是一个 修饰符 ： 只读事务 ，也就是属于该事务的数据库操作只能读取数据，而不 能修改数据。补充：只读事务中只是不允许修改那些其他事务也能访问到的表中的数据，对于临时表来说（我们 使用CREATE TMEPORARY TABLE 创建的表），由于它们只能在当前会话中可见，所有只读事务 其实也是可以对临时表进行增、删、改操作的。② READ WRITE ：标识当前事务是一个 读写事务 也可以修改数据。 ③ WITH CONSISTENT SNAPSHOT ：启动一致性读。 比如：START TRANSACTION READ ONLY; # 开启一个只读事务 START TRANSACTION READ ONLY, WITH CONSISTENT SNAPSHOT # 开启只读事务和一致性读 START TRANSACTION READ WRITE, WITH CONSISTENT SNAPSHOT # 开启读写事务和一致性读步骤2：一系列事务中的操作（主要是DML，不含DDL） 步骤3：提交事务 或 中止事务（即回滚事务）# 提交事务。当提交事务后，对数据库的修改是永久性的。 mysql> COMMIT; # 回滚事务。即撤销正在进行的所有没有提交的修改 mysql> ROLLBACK; # 将事务回滚到某个保存点。 mysql> ROLLBACK TO [SAVEPOINT] #其中关于SAVEPOINT相关操作有： # 在事务中创建保存点，方便后续针对保存点进行回滚。一个事务中可以存在多个保存点。 SAVEPOINT 保存点名称; # 删除某个保存点 RELEASE SAVEPOINT 保存点名称;2.2 隐式事务MySQL中有一个系统变量 autocommit ： mysql> SHOW VARIABLES LIKE 'autocommit'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set (0.01 sec)当然，如果我们想关闭这种 自动提交 的功能，可以使用下边两种方法之一：显式的的使用 START TRANSACTION 或者 BEGIN 语句开启一个事务。这样在本次事务提交或者回 滚前会暂时关闭掉自动提交的功能。把系统变量 autocommit 的值设置为 OFF ，就像这样：SET autocommit = OFF; #或 SET autocommit = 0;这样的话，我们写入的多条语句就算是属于同一个事务了，直到我们显式的写出C0MMIT语句来把这个事务提交掉，或者显式的写出ROLLBACK语句来把这个事务回滚掉。2.3 隐式提交数据的情况1.数据定义语言（Data definition language，缩写为：DDL） 数据库对象，指的就是 数据库、表、视图、存储过程等结构。当我们 CREATE、ALTER、DROP 等语句 去修改数据库对象时，就会隐式的提交前边语句所属于的事务。即：BEGIN; SELECT ... # 事务中的一条语句 UPDATE ... # 事务中的一条语句 ... # 事务中的其他语句 CREATE TABLE ... # 此语句会隐式的提交前边语句所属于的事务2. 隐式使用或修改mysql数据库中的表 当我们使用 ALTER USER 、 CREATE USER 、 DROP USER 、 GRANT 、 SET PASSWORD 等语句时也会隐式的提交前边语句所属于的事务。 3. 事务控制或关于锁定的语句 ①当我们在一个事务还没提交或者回滚时就又使用 START TRANSACTION 或者 BEGIN 语句开启了 另一个事务时，会隐式的提交上一个事务。即： BEGIN; SELECT ... # 事务中的一条语句 UPDATE ... # 事务中的一条语句 ... # 事务中的其他语句 BEGIN; # 此语句会隐式的提交前边语句所属于的事务②当前的 autocommit 系统变量的值为 OFF ，我们手动把它调为 ON 时，也会 隐式的提交前边语 句所属的事务。 ③使用 LOCK TABLES 、 UNLOCK TABLES 等关于锁定的语句也会 隐式的提交 前边语句所属的事务。 4. 加载数据的语句 使用 LOAD DATA 语句来批量往数据库中导入数据时，也会 隐式的提交前边语句所属的事务。 5. 关于MySQL复制的一些语句 使用 START SLAVE、STOP SLAVE、RESET SLAVE、CHANGE MASTER TO 等语句会隐式的提交前边语 句所属的事务 6. 其他的一些语句 使用 ANALYZE TABLE、CACHE INDEX、CAECK TABLE、FLUSH、LOAD INDEX INTO CACHE、 OPTIMIZE TABLE、REPAIR TABLE、RESET 等语句也会隐式的提交前边语句所属的事务。3. 事务隔离级别MySQL是一个 客户端／服务器 架构的软件，对于同一个服务器来说，可以有若干个客户端与之连接，每 个客户端与服务器连接上之后，就可以称为一个会话（ Session ）。每个客户端都可以在自己的会话 中 向服务器发出请求语句，一个请求语句可能是某个事务的一部分，也就是对于服务器来说可能同时处 理多个事务。事务有 隔离性的特性，理论上在某个事务 对某个数据进行访问 时，其他事务应该进行 排 队 ，当该事务提交之后，其他事务才可以继续访问这个数据。但是这样对 性能影响太大 , 我们既想保持事务的隔离性，又想让服务器在处理访问同一数据的多个事务时 性能影响太大 ，我们既想保 性能尽量高些 ，那就看二者如何权衡 取 舍了。3.1 SQL中的四种隔离级别1. 读未提交：脏读脏读 ：事务B读取到，事务A 还没有提交的数据(读取到临时数据)。2. 读已提交：不可重复读不可重复读：在一个事物内，同一条sql多次读取到的数据不一致（受其它事务影响）。3. 可重复读(MySql默认隔离级别)：幻读幻读：事务A的插入或者删除操作，会影响事务B内同一条查询sql的读取结果。4. 序列化读性能低下。3.2 MySQL支持的四种隔离级别不同的数据库厂商对SQL标准中规定的四种隔离级别支持不一样。比如，Oracle就只支持READ C0 MMITTED(默认隔离级别)和SERIALIZABLE隔离级别。MySQL虽然支持4种隔离级别，但与SQL标准中所规定的各级隔离级别允许发生的问题却有些出入，MySQL在REPEATABLE READ（可重复读）隔离级别下，使用MVCC多版本并发控制方式解决的幻读问题。MySQL的默认隔离级别为REPEATABLE READ，我们可以手动修改一下事务的隔离级别。# 查看隔离级别，MySQL 5.7.20的版本之前： mysql> SHOW VARIABLES LIKE 'tx_isolation'; +---------------+-----------------+ | Variable_name | Value | +---------------+-----------------+ | tx_isolation | REPEATABLE-READ | +---------------+-----------------+ 1 row in set (0.00 sec) # MySQL 5.7.20版本之后，引入transaction_isolation来替换tx_isolation # 查看隔离级别，MySQL 5.7.20的版本及之后： mysql> SHOW VARIABLES LIKE 'transaction_isolation'; +-----------------------+-----------------+ | Variable_name | Value | +-----------------------+-----------------+ | transaction_isolation | REPEATABLE-READ | +-----------------------+-----------------+ 1 row in set (0.02 sec) #或者不同MySQL版本中都可以使用的： SELECT @@transaction_isolation;3.3 如何设置事务的隔离级别通过下面的语句修改事务的隔离级别：SET [GLOBAL|SESSION] TRANSACTION ISOLATION LEVEL 隔离级别; #其中，隔离级别格式： > READ UNCOMMITTED > READ COMMITTED > REPEATABLE READ > SERIALIZABLE或者：SET [GLOBAL|SESSION] TRANSACTION_ISOLATION = '隔离级别' #其中，隔离级别格式： > READ-UNCOMMITTED > READ-COMMITTED > REPEATABLE-READ > SERIALIZABLE关于设置时使用GLOBAL或SESSION的影响： 使用 GLOBAL 关键字（在全局范围影响）： SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE; #或 SET GLOBAL TRANSACTION_ISOLATION = 'SERIALIZABLE';则：- 当前已经存在的会话无效 - 只对执行完该语句之后产生的会话起作用 使用 SESSION 关键字（在会话范围影响）： SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; #或 SET SESSION TRANSACTION_ISOLATION = 'SERIALIZABLE';则：- 对当前会话的所有后续的事务有效 - 如果在事务之间执行，则对后续的事务有效 - 该语句可以在已经开启的事务中间执行，但不会影响当前正在执行的事务 如果在服务器启动时想改变事务的默认隔离级别，可以修改启动参数transaction_isolation的值。 比如，在启动服务器时指定了transaction_isolation=SERIALIZABLE，那么事务的默认隔离界别就 从原来的REPEATABLE- READ变成了SERIALIZABLE。
1. 为什么需要数据库设计我们在设计数据表的时候，要考虑很多问题。比如：用户都需要什么数据？需要在数据表中保存哪些数据？如何保证数据表中数据的正确性，当插入、删除、更新的时候该进行怎样的约束检查？如何降低数据表的数据冗余度，保证数据表不会因为用户量的增长而迅速扩张？如何让负责数据库维护的人员更方便地使用数据库？使用数据库的应用场景也各不相同，可以说针对不同的情况，设计出来的数据表可能千差万别。现实情况中，面临的场景：当数据库运行了一段时间之后，我们才发现数据表设计的有问题。重新调整数据表的结构，就需要做数据迁移，还有可能影响程序的业务逻辑，以及网站正常的访问。如果是糟糕的数据库设计可能会造成以下问题：数据冗余、信息重复，存储空间浪费数据更新、插入、删除的异常无法正确表示信息丢失有效信息程序性能差良好的数据库设计则有以下优点：节省数据的存储空间能够保证数据的完整性方便进行数据库应用系统的开发总之，开始设置数据库的时候，我们就需要重视数据表的设计。为了建立冗余较小、结构合理的数据库，设计数据库时必须遵循一定的规则。2. 范 式2.1 范式简介在关系型数据库中，关于数据表设计的基本原则、规则就称为范式。可以理解为，一张数据表的设计结构需要满足的某种设计标准的级别 。要想设计一个结构合理的关系型数据库，必须满足一定的范式。2.2 范式都包括哪些目前关系型数据库有六种常见范式，按照范式级别，从低到高分别是：第一范式（1NF）、第二范式 （2NF）、第三范式（3NF）、巴斯-科德范式（BCNF）、第四范式(4NF）和第五范式（5NF，又称完美 范式）。数据库的范式设计越高阶，夯余度就越低，同时高阶的范式一定符合低阶范式的要求，满足最低要求的范式是第一范式（1NF）。在第一范式的基础上进一步满足更多规范的要求称为第二范式（2NF），其余范式以此类推。一般来说，在关系型数据库设计中，最高也就遵循到 BCNF , 普遍还是3NF 。但也不绝对，有时候为了提 高某些查询性能，我们还需要破坏范式规则，也就是反规范化。 2.3 键和相关属性的概念范式的定义会使用到主键和候选键，数据库中的键(Ky)由一个或者多个属性组成。数据表中常用的几种键和属性的定义：超键：能唯一标识元组的属性集叫做超键。候选键：如果超键不包括多余的属性，那么这个超键就是候选键。主键：用户可以从候选键中选择一个作为主键。外键：如果数据表R1中的某属性集不是R1的主键，而是另一个数据表R2的主键，那么这个属性集就是数据表R1的外键。主属性：包含在任一候选键中的属性称为主属性。非主属性：与主属性相对，指的是不包含在任何一个候选键中的属性。通常，我们也将候选键称之为“码”，把主键也称为“主码”。因为键可能是由多个属性组成的，针对单个属性，我们还可以用主属性和非主属性来进行区分。2.4 第一范式(1st NF)第一范式主要确保数据库中每个字段的值必须具有原子性，也就是说数据表中每个字段的值为 拆分的最小数据单元。 不可再次我们在设计某个字段的时候，对于字段X来说，不能把字段X拆分成字段X-1和字段X-2。事实上，任何的 DBMS都会满足第一范式的要求，不会将字段进行拆分。 举例：user 表的设计不符合第一范式 其中，user_info字段为用户信息，可以进一步拆分成更小粒度的字段，不符合数据库设计对第一范式的 要求。将user_info拆分后如下： 2.5 第二范式(2nd NF)第二范式要求，在满足第一范式的基础上，还要满足数据库里的每一条数据记录，都是可唯一标识的。 而且所有非主键字段，都必须完全依赖主键，不能只依赖主键的一部分。如果知道主键的所有属性的 值，就可以检索到任何元组（行）的任何属性的任何值。（要求中的主键，其实可以扩展替换为候选 键）。 举例1： 成绩表 （学号，课程号，成绩）关系中，（学号，课程号）可以决定成绩，但是学号不能决定成绩，课 程号也不能决定成绩，所以“（学号，课程号）→成绩”就是完全依赖关系 。 举例2： 比赛表 player_game ，里面包含球员编号、姓名、年龄、比赛编号、比赛时间和比赛场地等属性，这 里候选键和主键都为（球员编号，比赛编号），我们可以通过候选键（或主键）来决定如下的关系：(球员编号, 比赛编号) → (姓名, 年龄, 比赛时间, 比赛场地，得分)但是这个数据表不满足第二范式，因为数据表中的字段之间还存在着如下的对应关系： (球员编号) → (姓名，年龄) (比赛编号) → (比赛时间, 比赛场地)对于非主属性来说，并非完全依赖候选键。这样会产生怎样的问题呢？数据冗余 ：如果一个球员可以参加 m 场比赛，那么球员的姓名和年龄就重复了 m-1 次。一个比赛 也可能会有 n 个球员参加，比赛的时间和地点就重复了 n-1 次。插入异常 ：如果我们想要添加一场新的比赛，但是这时还没有确定参加的球员都有谁，那么就没 法插入。删除异常 ：如果我要删除某个球员编号，如果没有单独保存比赛表的话，就会同时把比赛信息删 除掉。更新异常 ：如果我们调整了某个比赛的时间，那么数据表中所有这个比赛的时间都需要进行调 整，否则就会出现一场比赛时间不同的情况。为了避免出现上述的情况，我们可以把球员比赛表设计为下面的三张表。 这样的话，每张数据表都符合第二范式，也就避免了异常情况的发生。1NF 告诉我们字段属性需要是原子性的，而 2NF 告诉我们一张表就是一个独立的对象，一张表只表达一个意思。2.6 第三范式(3rd NF)第三范式是在第二范式的基础上，确保数据表中的每一个非主键字段都和主键字段直接相关，也就是说，要求数据表中的所有非主键字段不能依赖于其他非主键字段。（即，不能存在非主属性A依赖于非 主属性B，非主属性B依赖于主键C的情况，即存在“A->B->C"的决定关系）通俗地讲，该规则的意思是所有非主键属性之间不能有依赖关系，必须相互独立。 这里的主键可以扩展为候选键。 举例 ：商品类别名称依赖于商品类别编号，不符合第三范式。 修改： 表1：符合第三范式的 商品类别表 的设计 表2：符合第三范式的 商品表 的设计 商品表goods通过商品类别id字段（category_id）与商品类别表goods_category进行关联。2.7 小结关于数据表的设计，有三个范式要遵循！(1)第一范式(1NF),确保每列保持原子性数据库的每一列都是不可分割的原子数据项，不可再分的最小数据单元，而不能是集合、数组、记录等非原子数据项。(2)第二范式(2NF),确保每列都和主键完全依赖尤其在复合主键的情况下，非主键部分不应该依赖于部分主键。(3)第三范式(3NF)确保每列都和主键列直接相关，而不是间接相关范式的优点：数据的标准化有助于消除数据库中的数据冗余，第三范式(3NF)通常被认为在性能、扩展性和数据完整性方面达到了最好的平衡。范式的缺点：范式的使用，可能降低查询的效率。因为范式等级越高，设计出来的数据表就越多、越精细，数据的冗余度就越低，进行数据查询的时候就可能需要关联多张表，这不但代价昂贵，也可能使一些索引策略无效。范式只是提出了设计的标准，实际上设计数据表时，未必一定要符合这些标准。开发中，我们会出现为了性能和读取效率违反范式化的原则，通过增加少量的冗余或重复的数据来提高数据库的读性能，减少关联查询，joi表的次数，实现空间换取时间的目的。因此在实际的设计过程中要理论结合实际，灵活运用。3. 反范式化3.1 概述有的时候不能简单按照规范要求设计数据表，因为有的数据看以冗余，其实对业务来说十分重要。这个时候，我们就要遵循业务优先的原则，首先满足业务需求，再尽量减少冗余。如果数据库中的数据量比较大，系统的UV和PV访问频次比较高，则完全按照MySQL的三大范式设计数据表，读数据时会产生大量的关联查询，在一定程度上会影响数据库的读性能。如果我们想对查询效率进行优化，反范式优化也是一种优化思路。此时，可以通过在数据表中增加冗余字段来提高数据库的读性能。规范化 vs 性能 1. 为满足某种商业目标 , 数据库性能比规范化数据库更重要 2. 在数据规范化的同时 , 要综合考虑数据库的性能 3. 通过在给定的表中添加额外的字段，以大量减少需要从中搜索信息所需的时间 4. 通过在给定的表中插入计算列，以方便查询 3.2 应用举例 3.3 反范式的新问题存储空间变大了一个表中字段做了修改，另一个表中冗余的字段也需要做同步修改，否则 数据不一致若采用存储过程来支持数据的更新、删除等额外操作，如果更新频繁，会非常消耗系统资源在 数据量小的情况下，反范式不能体现性能的优势，可能还会让数据库的设计更加复杂3.4 反范式的适用场景当冗余信息有价值或者能 大幅度提高查询效率 的时候，我们才会采取反范式的优化。 1. 增加冗余字段的建议 增加冗余字段一定要符合如下两个条件。只要满足这两个条件，才可以考虑增加夯余字段。 1）这个冗余字段 不需要经常进行修改。 2）这个冗余字段 查询的时候不可或缺。 2. 历史快照、历史数据的需要 在现实生活中，我们经常需要一些冗余信息，比如订单中的收货人信息，包括姓名、电话和地址等。每次发生的订单收货信息，都属于历史快照 ，需要进行保存，但用户可以随时修改自己的信息，这时保存这些冗余信息是非常有必要的。 反范式优化也常用在数据仓库 的设计中，因为数据仓库通常 存储历史数据 ，对增删改的实时性要求不强，对历史数据的分析需求强。这时适当允许数据的冗余度，更方便进行数据分析。 我简单总结下数据仓库和数据库在使用上的区别： 数据库设计的目的在于 捕捉数据，而数据仓库设计的目的在于 分析数据。2.数据库对数据的增删改实时性要求强，需要存储在线的用户数据，而数据仓库存储的一般是 历史数据。数据库设计需要 尽量避免冗余，但为了提高查询效率也允许一定的冗余度，而数据仓库在设计上更偏向采用反范式设计。4. BCNF(巴斯范式)人们在3NF的基础上进行了改进，提出了巴斯范式（BCNF），页脚巴斯 - 科德范式（Boyce - Codd Normal Form）。BCNF被认为没有新的设计规范加入，只是对第三范式中设计规范要求更强，使得数据库冗余度更小。所以，称为是 修正的第三范式，或 扩充的第三范式，BCNF不被称为第四范式。 若一个关系达到了第三范式，并且它只有一个候选键，或者它的每个候选键都是单属性，则该关系自然达到BC范式。 一般来说，一个数据库设符合3NF或者BCNF就可以了。5. ER模型数据库设计是牵一发而动全身的。那有没有什么办法提前看到数据库的全貌呢？比如需要哪些数据表、数据表中应该有哪些字段，数据表与数据表之间有什么关系、通过什么字段进行连接，等等。这样我们才能进行整体的梳理和设计。其实，E模型就是一个这样的工具。ER模型也叫作实体关系模型，是用来描述现实生活中客观存在的事物、事物的属性，以及事物之间关系的一种数据模型。在开发基于数据库的信息系统的设计阶段，通常使用E模型来描述信息需求和信息特性，帮助我们理清业务逻辑，从而设计出优秀的数据库。5.1 ER模型包括哪些要素？ ER 模型中有三个要素，分别是实体、属性和关系。 实体 :可以看做是数据对象，往往对应于现实生活中的真实存在的个体。在 ER 模型中，用 矩形 来表 示。实体分为两类，分别是 强实体 和 弱实体 。强实体是指不依赖于其他实体的实体；弱实体是指对另 一个实体有很强的依赖关系的实体。 属性 :则是指实体的特性。比如超市的地址、联系电话、员工数等。在 ER 模型中用 椭圆形 来表示。 关系 :则是指实体之间的联系。比如超市把商品卖给顾客，就是一种超市与顾客之间的联系。在 ER 模 型中用 菱形 来表示。 注意：实体和属性不容易区分。这里提供一个原则：我们要从系统整体的角度出发去看，可以独立存在的是实体，不可再分的是属性。也就是说，属性不能包含其他属性。5.2 关系的类型在 ER 模型的 3 个要素中，关系又可以分为 3 种类型，分别是 一对一、一对多、多对多。 一对一 ：指实体之间的关系是一一对应的，比如个人与身份证信息之间的关系就是一对一的关系。一个人只能有一个身份证信息，一个身份证信息也只属于一个人。 一对多 ：指一边的实体通过关系，可以对应多个另外一边的实体。相反，另外一边的实体通过这个关 系，则只能对应唯一的一边的实体。比如说，我们新建一个班级表，而每个班级都有多个学生，每个学 生则对应一个班级，班级对学生就是一对多的关系。 多对多 ：指关系两边的实体都可以通过关系对应多个对方的实体。比如在进货模块中，供货商与超市之 间的关系就是多对多的关系，一个供货商可以给多个超市供货，一个超市也可以从多个供货商那里采购 商品。再比如一个选课表，有许多科目，每个科目有很多学生选，而每个学生又可以选择多个科目，这 就是多对多的关系。6. 数据表的设计原则综合以上内容，总结出数据表设计的一般原则："三少一多"1. 数据表的个数越少越好RDBMS的核心在于对实体和联系的定义，也就是E-R图(Entity Relationship Diagram)，数据表越少，证明实体和联系设计得越简洁，既方便理解又方便操作。2. 数据表中的字段个数越少越好字段个数越多，数据冗余的可能性越大。设置字段个数少的前提是各个字段相互独立，而不是某个字段的取值可以由其他字段计算出来。当然字段个数少是相对的，我们通常会在数据冗余和检索效率中进行平衡。3. 数据表中联合主键的字段个数越少越好设置主键是为了确定唯一性，当一个字段无法确定唯一性的时候，就需要采用联合主键的方式（也就是用多个字段来定义一个主键)。联合主键中的字段越多，占用的索引空间越大，不仅会加大理解难度，还会增加运行时间和索引空间，因此联合主键的字段个数越少越好。4. 使用主键和外键越多越好数据库的设计实际上就是定义各种表，以及各种字段之间的关系。这些关系越多，证明这些实体之间的冗余度越低，利用度越高。这样做的好处在于不仅保证了数据表之间的独立性，还能提升相互之间的关联使用率。“三少一多”原则的核心就是简单可复用。简单指的是用更少的表、更少的字段、更少的联合主键字段来完成数据表的设计。可复用则是通过主键、外键的使用来增强数据表之间的复用率。因为一个主键可以理解是一张表的代表。键设计得越多，证明它们之间的利用率越高。注意：这个原则并不是绝对的，有时候我们需要牺牲数据的冗余度来换取数据处理的效率。7. 数据库对象编写建议1 关于库【强制】库的名称必须控制在32个字符以内，只能使用英文字母、数字和下划线，建议以英文字 母开头。【强制】库名中英文 一律小写 ，不同单词采用 下划线 分割。须见名知意。【强制】库的名称格式：业务系统名称_子系统名。【强制】库名禁止使用关键字（如type,order等）。【强制】创建数据库时必须 显式指定字符集 ，并且字符集只能是utf8或者utf8mb4。 创建数据库 SQL举例：CREATE DATABASE crm_fund DEFAULT CHARACTER SET 'utf8' ;【建议】对于程序连接数据库账号，遵循 权限最小原则 使用数据库账号只能在一个DB下使用，不 准跨库。程序使用的账号 原则上不准有drop权限 。【建议】临时库以 tmp_ 为前缀，并以日期为后缀； 备份库以 bak_ 为前缀，并以日期为后缀。2 关于表、列【强制】表和列的名称必须控制在32个字符以内，表名只能使用英文字母、数字和下划线，建议 以 英文字母开头 。【强制】 表名、列名一律小写 ，不同单词采用下划线分割。须见名知意。【强制】表名要求有模块名强相关，同一模块的表名尽量使用 统一前缀 。比如：crm_fund_item【强制】创建表时必须 显式指定字符集 为utf8或utf8mb4。【强制】表名、列名禁止使用关键字（如type,order等）。【强制】创建表时必须 显式指定表存储引擎 类型。如无特殊需求，一律为InnoDB。【强制】建表必须有comment。【强制】字段命名应尽可能使用表达实际含义的英文单词或 缩写 。如：公司 ID，不要使用 corporation_id, 而用corp_id 即可。【强制】布尔值类型的字段命名为 is_描述 。如member表上表示是否为enabled的会员的字段命 名为 is_enabled。【强制】禁止在数据库中存储图片、文件等大的二进制数据 通常文件很大，短时间内造成数据量快 速增长，数据库进行数据库读取时，通常会进行大量的随 机IO操作，文件很大时，IO操作很耗 时。通常存储于文件服务器，数据库只存储文件地址信息。【建议】建表时关于主键： 表必须有主键 (1)强制要求主键为id，类型为int或bigint，且为 auto_increment 建议使用unsigned无符号型。 (2)标识表里每一行主体的字段不要设为主键，建议 设为其他字段如user_id，order_id等，并建立 unique key索引。因为如果设为主键且主键值为随机 插入，则会导致innodb内部页分裂和大量随 机I/O，性能下降。【建议】核心表（如用户表）必须有行数据的 创建时间字段 （create_time）和 最后更新时间字段 （update_time），便于查问题。【建议】表中所有字段尽量都是 NOT NULL 属性，业务可以根据需要定义 DEFAULT值 。 因为使 用 NULL值会存在每一行都会占用额外存储空间、数据迁移容易出错、聚合函数计算结果偏差等问 题。【建议】所有存储相同数据的 列名和列类型必须一致 （一般作为关联列，如果查询时关联列类型 不一致会自动进行数据类型隐式转换，会造成列上的索引失效，导致查询效率降低）。【建议】中间表（或临时表）用于保留中间结果集，名称以 tmp_ 开头。 备份表用于备份或抓取源 表快照，名称以 bak_ 开头。中间表和备份表定期清理。【示范】一个较为规范的建表语句：CREATE TABLE user_info ( `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', `user_id` bigint(11) NOT NULL COMMENT '用户id', `username` varchar(45) NOT NULL COMMENT '真实姓名', `email` varchar(30) NOT NULL COMMENT '用户邮箱', `nickname` varchar(45) NOT NULL COMMENT '昵称', `birthday` date NOT NULL COMMENT '生日', `sex` tinyint(4) DEFAULT '0' COMMENT '性别', `short_introduce` varchar(150) DEFAULT NULL COMMENT '一句话介绍自己，最多50个汉 字', `user_resume` varchar(300) NOT NULL COMMENT '用户提交的简历存放地址', `user_register_ip` int NOT NULL COMMENT '用户注册时的源ip', `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时 间', `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间', `user_review_status` tinyint NOT NULL COMMENT '用户资料审核状态，1为通过，2为审核 中，3为未 通过，4为还未提交审核', PRIMARY KEY (`id`), UNIQUE KEY `uniq_user_id` (`user_id`), KEY `idx_username`(`username`), KEY `idx_create_time_status`(`create_time`,`user_review_status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='网站用户基本信息【建议】创建表时，可以使用可视化工具。这样可以确保表、字段相关的约定都能设置上。 实际上，我们通常很少自己写 DDL 语句，可以使用一些可视化工具来创建和操作数据库和数据表。 可视化工具除了方便，还能直接帮我们将数据库的结构定义转化成 SQL 语言，方便数据库和数据表结构 的导出和导入。3 关于索引【强制】InnoDB表必须主键为id int/bigint auto_increment，且主键值 禁止被更新 。【强制】InnoDB和MyISAM存储引擎表，索引类型必须为 BTREE 。【建议】主键的名称以 pk_ 开头，唯一键以 uni_ 或 uk_ 开头，普通索引以 idx_ 开头，一律使用小 写格式，以字段的名称或缩写作为后缀。【建议】多单词组成的columnname，取前几个单词首字母，加末单词组成column_name。如: sample 表 member_id 上的索引：idx_sample_mid。【建议】单个表上的索引个数 不能超过6个 。【建议】在建立索引时，多考虑建立 联合索引 ，并把区分度最高的字段放在最前面。【建议】在多表 JOIN 的SQL里，保证被驱动表的连接列上有索引，这样JOIN 执行效率最高。【建议】建表或加索引时，保证表里互相不存在 冗余索引 。 比如：如果表里已经存在key(a,b)， 则key(a)为冗余索引，需要删除。4 SQL编写【强制】程序端SELECT语句必须指定具体字段名称，禁止写成 *。【建议】程序端insert语句指定具体字段名称，不要写成INSERT INTO t1 VALUES(…)。【建议】除静态表或小表（100行以内），DML语句必须有WHERE条件，且使用索引查找。【建议】INSERT INTO…VALUES(XX),(XX),(XX).. 这里XX的值不要超过5000个。 值过多虽然上线很 快，但会引起主从同步延迟。【建议】SELECT语句不要使用UNION，推荐使用UNION ALL，并且UNION子句个数限制在5个以 内。【建议】线上环境，多表 JOIN 不要超过5个表。【建议】减少使用ORDER BY，和业务沟通能不排序就不排序，或将排序放到程序端去做。ORDER BY、GROUP BY、DISTINCT 这些语句较为耗费CPU，数据库的CPU资源是极其宝贵的。【建议】包含了ORDER BY、GROUP BY、DISTINCT 这些查询的语句，WHERE 条件过滤出来的结 果 集请保持在1000行以内，否则SQL会很慢。【建议】对单表的多次alter操作必须合并为一次 对于超过100W行的大表进行alter table，必须经 过DBA审核，并在业务低峰期执行，多个alter需整 合在一起。 因为alter table会产生 表锁 ，期间 阻塞对于该表的所有写入，对于业务可能会产生极 大影响。【建议】批量操作数据时，需要控制事务处理间隔时间，进行必要的sleep。【建议】事务里包含SQL不超过5个。 因为过长的事务会导致锁数据较久，MySQL内部缓存、连接 消耗过多等问题。【建议】事务里更新语句尽量基于主键或UNIQUE KEY，如UPDATE… WHERE id=XX; 否则会产生 间隙锁，内部扩大锁定范围，导致系统性能下降，产生死锁。8. PowerDesigner的使用PowerDesigner是一款开发人员常用的数据库建模工具，用户利用该软件可以方便地制作 数据流程图 、 概念数据模型 、 物理数据模型 ，它几乎包括了数据库模型设计的全过程，是Sybase公司为企业建模和 设 计提供的一套完整的集成化企业级建模解决方案。
普通索引 vs 唯一索引 在不同的业务场景下，应该选择普通索引，还是唯一索引？假设你在维护一个居民系统，每个人都有一个唯一的身份证号，而且业务代码已经保证了不会写入两个重复的身份证号。如果居民系统需要按照身份证号查姓名：select name from CUser where id_card ='xxxxxxxyyyyyyzzzzz';所以，你一定会考虑在id_card字段上建索引。由于身份证号字段比较大，不建议把身份证号当做主键。现在有两个选择，要么给id_card字段创建唯一索引，要么创建一个普通索引。如果业务代码已经保证了不会写入重复的身份证号，那么这两个选择逻辑上都是正确的。从性能的角度考虑，你选择唯一索引还是普通索引呢？选择的依据是什么呢？ 假设，我们有一个主键列为ID的表，表中有字段k，并且在k上有索引，假设字段 k 上的值都不重复。 这个表的建表语句是： create table test( id int primary key, k int not null, name varchar(16), index (k) )engine=InnoDB;表中R1~R5的(ID,k)值分别为(100,1)、(200,2)、(300,3)、(500,5)和(600,6)。1 查询过程 假设，执行查询的语句是 select id from test where k=5。 对于普通索引来说，查找到满足条件的第一个记录(5,500)后，需要查找下一个记录，直到碰到第一个不满足k=5条件的记录。对于唯一索引来说，由于索引定义了唯一性，查找到第一个满足条件的记录后，就会停止继续检 索。那么，这个不同带来的性能差距会有多少呢？答案是， 微乎其微 。 你知道的，noDB的数据是按数据页为单位来读写的。也就是说，当需要读一条记录的时候，并不是将这个记录本身从磁盘读出来，而是以页为单位，将其整体读入内存。在noDB中，每个数据页的大小默认是16KB。因为引擎是按页读写的，所以说，当找到k=5的记录的时候，它所在的数据页就都在内存里了。那么，对于普通索引来说，要多做的那一次“查找和判断下一条记录”的操作，就只需要一次指针寻找和一次计算。当然，如果k=5这个记录刚好是这个数据页的最后一个记录，那么要取下一个记录，必须读取下一个数据页，这个操作会稍微复杂一些。但是，我们之前计算过，对于整型字段，一个数据页可以放近千个ky，因此出现这种情况的概率会很低。所以我们计算平均性能差异时，仍可以认为这个操作成本对于现在的CPU来说可以忽略不计。2 更新过程 为了说明普通索引和唯一索引对更新语句性能的影响这个问题，介绍一下change buffer。当需要更新一个数据页时，如果数据页在内存中就直接更新，而如果这个数据页还没有在内存中的话， 在不影响数据一致性的前提下， InooDB会将这些更新操作缓存在change buffer中 ，这样就不需要从磁盘中读入这个数据页了。在下次查询需要访问这个数据页的时候，将数据页读入内存，然后执行change buffer中与这个页有关的操作。通过这种方式就能保证这个数据逻辑的正确性。 将change buffer中的操作应用到原数据页，得到最新结果的过程称为 merge 。除了 访问这个数据页 会 触 发merge外，系统有后台线程会定期 merge。在 数据库正常关闭（shutdown） 的过程中，也会执行 merge 操作。 如果能够将更新操作先记录在change buffer， 减少读磁盘 ，语句的执行速度会得到明显的提升。而 且， 数据读入内存是需要占用 buffer pool 的，所以这种方式还能够 避免占用内存 ，提高内存利用率。那么，什么条件下可以使用change bufferl呢？对于唯一索引来说，所有的更新操作都要先判断这个操作是否违反唯一性约束。比如，要插入(4,400这个记录就要先判断现在表中是否已经存在k二4的记录，而这必须要将数据页读入内存才能判断。如果都已经读入到内存了，那直接更新内存会更快，就没必要使用change buffer了。因此，唯一索引的更新就不能使用change buffer,实际上也只有普通索引可以使用。change buffer用的是buffer pool里的内存，因此不能无限增大。change buffer的大小，可以通过参数innodb_change_buffer_max_size来动态设置。这个参数设置为58的时候，表示change buffer的大小最多只能占用ouffer pool的50%。如果要在这张表中插入一个新记录(4,400)的话，nnoDB的处理流程是怎样的？第一种情况是，这个记录要更新的目标页在内存中。这时：对于唯一索引来说，找到3和5之间的位置，判断为没有冲突，插入这个值，语句执行结束：对于普通索引来说，找到3和5之间的位置，插入这个值，语句执行结束。这样看来，普通索引和唯一索引对更新语句性能影响的差别，只是一个判断，只会耗费微小的CPU时间。第二种情况是，这个记录要更新的目标页不在内存中。这时：对于唯一索引来说，需要将数据页读入内存，判断到没有冲突，插入这个值，语句执行结束：对于普通索引来说，则是将更新记录在change buffer,语句执行就结束了.将数据从磁盘读入内存涉及随机lo的访问，是数据库里面成本最高的操作之一。change buffer因为减少了随机磁盘访问，所以对更新性能的提升是会很明显的.
索引下推 (就是不着急回表，减少回表数量)更多的是在联合索引使用Index Condition Pushdown(ICP)是MySQL 5.6中新特性，是一种在存储引擎层使用索引过滤数据的一种优化方式。ICP可以减少存储引擎访问基表的次数以及MySQL服务器访问存储引擎的次数。1 使用前后的扫描过程 在不使用ICP索引扫描的过程： storage层：只将满足index key条件的索引记录对应的整行记录取出，返回给server层 server 层：对返回的数据，使用后面的where条件过滤，直至返回最后一行。 使用ICP扫描的过程： storage层： 首先将index key条件满足的索引记录区间确定，然后在索引上使用index filter进行过滤。将满足的index filter条件的索引记录才去回表取出整行记录返回server层。不满足index filter条件的索引记录丢弃，不回 表、也不会返回server层。 server 层： 对返回的数据，使用table filter条件做最后的过滤。 使用前后的成本差别 使用前存储层多返回了需要被index filter过滤掉的整行记录 使用ICP后直接就去掉了不满足index filter条件的记录，省去了他们回表和传递到server层的成本。 ICP的 加速效果取决于在存储引擎内通过 ICP筛选 掉的数据的比例。10.2 ICP的使用条件 ①只能用于二级索引(secondary index)②explain显示的执行计划中type值（join 类型）为 range 、 ref 、 eq_ref 或者 ref_or_null 。 ③并非全部where条件都可以用ICP筛选，如果where条件的字段不在索引列中，还是要读取整表的记录 到server端做where过滤。④ICP可以用于MyISAM和InnnoDB存储引擎 ⑤MySQL 5.6版本的不支持分区表的ICP功能，5.7版本的开始支持。⑥当SQL使用覆盖索引时，不支持ICP优化方法。
什么是覆盖索引？理解方式一：索引是高效找到行的一个方法，但是一般数据库也能使用索引找到一个列的数据，因此它 不必读取整个行。毕竟索引叶子节点存储了它们索引的数据；当能通过读取索引就可以得到想要的数 据，那就不需要读取行了。一个索引包含了满足查询结果的数据就叫做覆盖索引。理解方式二：非聚簇复合索引的一种形式，它包括在查询里的SELECT、JOIN和WHERE子句用到的所有 列 （即建索引的字段正好是覆盖查询条件中所涉及的字段）。 简单说就是， 索引列+主键 包含 SELECT 到 FROM之间查询的列 。 举例：select age from studen where age > 123;覆盖索引的利弊好处：1.避免Innodb表进行索引的二次查询（回表）2.可以把随机I/O变成顺序I/O加快查询效率弊端：索引字段的维护总是有代价的。因此，在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这是业务DBA,或者称为业务数据架构师的工作。