├── .gitattributes ├── .gitignore ├── README.md ├── deploy.sh ├── docs ├── .vuepress │ ├── config.js │ ├── enhanceApp.js │ ├── public │ │ ├── favicon.ico │ │ ├── hero.png │ │ ├── manifest.json │ │ └── mlogo.svg │ └── styles │ │ ├── fonts │ │ ├── JetBrainsMono-1.0.3 │ │ │ └── woff2 │ │ │ │ ├── JetBrainsMono-Bold-Italic.woff2 │ │ │ │ ├── JetBrainsMono-Bold.woff2 │ │ │ │ ├── JetBrainsMono-ExtraBold-Italic.woff2 │ │ │ │ ├── JetBrainsMono-ExtraBold.woff2 │ │ │ │ ├── JetBrainsMono-Italic.woff2 │ │ │ │ ├── JetBrainsMono-Medium-Italic.woff2 │ │ │ │ ├── JetBrainsMono-Medium.woff2 │ │ │ │ └── JetBrainsMono-Regular.woff2 │ │ └── index.styl │ │ └── index.styl ├── README.md ├── ali-new-retail │ ├── 10 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── 06.md │ │ ├── 07.md │ │ ├── 08.md │ │ ├── 09.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200618212254757.png │ │ │ ├── image-20200618212452578.png │ │ │ ├── image-20200618212715914.png │ │ │ ├── image-20200618212937247.png │ │ │ ├── image-20200618213540418.png │ │ │ ├── image-20200618214243848.png │ │ │ ├── image-20200618214534441.png │ │ │ ├── image-20200618215047621.png │ │ │ ├── image-20200618220204807.png │ │ │ ├── image-20200618220337563.png │ │ │ ├── image-20200620145805281.png │ │ │ ├── image-20200620160426946.png │ │ │ ├── image-20200620162209185.png │ │ │ ├── image-20200620214923711.png │ │ │ ├── image-20200620221957256.png │ │ │ ├── image-20200621144637535.png │ │ │ ├── image-20200621150223525.png │ │ │ ├── image-20200621170407068.png │ │ │ ├── image-20200621170720454.png │ │ │ └── image-20200621170912726.png │ ├── 11 │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200621181612366.png │ │ │ ├── image-20200621181834358.png │ │ │ ├── image-20200621182420663.png │ │ │ ├── image-20200621182700872.png │ │ │ ├── image-20200621182853195.png │ │ │ ├── image-20200621183014367.png │ │ │ ├── image-20200621183126068.png │ │ │ ├── image-20200621183333572.png │ │ │ └── image-20200621184056678.png │ ├── 12 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200621211931122.png │ │ │ ├── image-20200621213655845.png │ │ │ ├── image-20200621225537824.png │ │ │ ├── image-20200623215307022.png │ │ │ ├── image-20200623222239413.png │ │ │ ├── image-20200623225211701.png │ │ │ ├── image-20200627110238826.png │ │ │ ├── image-20200627111909836.png │ │ │ ├── image-20200627112021563.png │ │ │ ├── image-20200627112755656.png │ │ │ └── image-20200627121618088.png │ ├── 01 │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200530200718891.png │ │ │ ├── image-20200530200820039.png │ │ │ ├── image-20200530200935496.png │ │ │ └── summary.png │ ├── 02 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200530211010903.png │ │ │ ├── image-20200530214432158.png │ │ │ ├── image-20200531205652930.png │ │ │ └── image-20200531210623856.png │ ├── 03 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200531215455564.png │ │ │ ├── image-20200531220337087.png │ │ │ ├── image-20200531221303648.png │ │ │ ├── image-20200531221519615.png │ │ │ ├── image-20200531222154285.png │ │ │ ├── image-20200531222334973.png │ │ │ ├── image-20200531222727132.png │ │ │ ├── image-20200531222858076.png │ │ │ ├── image-20200601213905083.png │ │ │ ├── image-20200601214146679.png │ │ │ ├── image-20200601214239167.png │ │ │ ├── image-20200601214756148.png │ │ │ ├── image-20200602215853158.png │ │ │ ├── image-20200602220827643.png │ │ │ ├── image-20200602221316208.png │ │ │ ├── image-20200602221657199.png │ │ │ └── image-20200602222642797.png │ ├── 04 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── 06.md │ │ ├── 07.md │ │ ├── 08.md │ │ ├── 09.md │ │ ├── 10.md │ │ ├── 11.md │ │ ├── 12.md │ │ ├── 13.md │ │ ├── 14.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200602223704818.png │ │ │ ├── image-20200602225128185.png │ │ │ ├── image-20200602230528749.png │ │ │ ├── image-20200603213714257.png │ │ │ ├── image-20200603214945548.png │ │ │ ├── image-20200603215218640.png │ │ │ ├── image-20200603215422713.png │ │ │ ├── image-20200603215726550.png │ │ │ ├── image-20200603215918744.png │ │ │ ├── image-20200603221242071.png │ │ │ ├── image-20200603222446159.png │ │ │ ├── image-20200603225440768.png │ │ │ ├── image-20200603230456735.png │ │ │ ├── image-20200604210829879.png │ │ │ ├── image-20200604211023017.png │ │ │ ├── image-20200604211722057.png │ │ │ ├── image-20200604211943017.png │ │ │ ├── image-20200604212817714.png │ │ │ ├── image-20200604213521317.png │ │ │ ├── image-20200604215701973.png │ │ │ ├── image-20200604220358810.png │ │ │ ├── image-20200604221848513.png │ │ │ ├── image-20200604222316161.png │ │ │ ├── image-20200606152330688.png │ │ │ ├── image-20200606152633397.png │ │ │ ├── image-20200606153031009.png │ │ │ ├── image-20200606153653899.png │ │ │ ├── image-20200606154802659.png │ │ │ ├── image-20200606155611696.png │ │ │ ├── image-20200606163539733.png │ │ │ ├── image-20200606163923678.png │ │ │ ├── image-20200606164933171.png │ │ │ ├── image-20200606171635552.png │ │ │ ├── image-20200606171848575.png │ │ │ ├── image-20200606172417791.png │ │ │ ├── image-20200606204651069.png │ │ │ ├── image-20200606210946028.png │ │ │ ├── image-20200606213335284.png │ │ │ ├── image-20200606213452640.png │ │ │ ├── image-20200607100906653.png │ │ │ ├── image-20200607102720626.png │ │ │ ├── image-20200607103831302.png │ │ │ ├── image-20200607122626332.png │ │ │ ├── image-20200607123603057.png │ │ │ ├── image-20200607125625266.png │ │ │ └── image-20200607125645561.png │ ├── 05 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── 06.md │ │ ├── 07.md │ │ ├── 08.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200607140909217.png │ │ │ ├── image-20200607141059856.png │ │ │ ├── image-20200607141942571.png │ │ │ ├── image-20200607152047353.png │ │ │ ├── image-20200607173145363.png │ │ │ ├── image-20200607180027818.png │ │ │ ├── image-20200607203427729.png │ │ │ ├── image-20200607210627524.png │ │ │ ├── image-20200607211346366.png │ │ │ ├── image-20200607211404137.png │ │ │ ├── image-20200607211831410.png │ │ │ └── image-20200607212441588.png │ ├── 06 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── 06.md │ │ ├── 07.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200609214755323.png │ │ │ ├── image-20200609220247456.png │ │ │ ├── image-20200609221113157.png │ │ │ ├── image-20200610214229906.png │ │ │ ├── image-20200610223023285.png │ │ │ ├── image-20200610230140947.png │ │ │ ├── image-20200611223654450.png │ │ │ └── image-20200611224913567.png │ ├── 07 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200613215435043.png │ │ │ ├── image-20200613215906767.png │ │ │ ├── image-20200613220518698.png │ │ │ ├── image-20200613225041583.png │ │ │ ├── image-20200613231042478.png │ │ │ ├── image-20200614085126417.png │ │ │ ├── image-20200614091852158.png │ │ │ └── image-20200614111515949.png │ ├── 08 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200614150143627.png │ │ │ └── image-20200614182205307.png │ ├── 09 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── 06.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200614211428024.png │ │ │ ├── image-20200614212702883.png │ │ │ ├── image-20200614213149887.png │ │ │ ├── image-20200614213202049.png │ │ │ ├── image-20200614213454879.png │ │ │ ├── image-20200614213614537.png │ │ │ ├── image-20200614214714808.png │ │ │ ├── image-20200614214903784.png │ │ │ ├── image-20200614223408493.png │ │ │ ├── image-20200615213206621.png │ │ │ ├── image-20200615213442608.png │ │ │ ├── image-20200615213515494.png │ │ │ ├── image-20200615215035696.png │ │ │ ├── image-20200615215050956.png │ │ │ ├── image-20200616225005505.png │ │ │ ├── image-20200616233723811.png │ │ │ ├── image-20200616234217657.png │ │ │ ├── image-20200616234721341.png │ │ │ ├── image-20200617214708928.png │ │ │ └── image-20200617214826011.png │ ├── README.md │ └── index.js ├── high-performance │ ├── 01 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── 06.md │ │ ├── 07.md │ │ ├── 08.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200415143832875.png │ │ │ ├── image-20200506183846443.png │ │ │ └── image-20200506183914938.png │ ├── 02 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200507135121390.png │ │ │ ├── image-20200507153735711.png │ │ │ ├── image-20200507154740314.png │ │ │ ├── image-20200507155740725.png │ │ │ ├── image-20200507165234295.png │ │ │ ├── image-20200507165314790.png │ │ │ ├── image-20200507165356497.png │ │ │ ├── image-20200507165457413.png │ │ │ ├── image-20200507171607205.png │ │ │ ├── image-20200507171727766.png │ │ │ ├── image-20200507172050613.png │ │ │ ├── image-20200507182746584.png │ │ │ ├── image-20200507182824646.png │ │ │ └── image-20200507182841194.png │ ├── 03 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200508111211415.png │ │ │ ├── image-20200508113733111.png │ │ │ ├── image-20200508142528230.png │ │ │ ├── image-20200508143136237.png │ │ │ ├── image-20200508143656065.png │ │ │ ├── image-20200508152816361.png │ │ │ ├── image-20200508153222923.png │ │ │ ├── image-20200508162508331.png │ │ │ ├── image-20200508164432061.png │ │ │ ├── image-20200508173048217.png │ │ │ ├── image-20200508180245780.png │ │ │ ├── image-20200508180605954.png │ │ │ ├── image-20200508181144459.png │ │ │ ├── image-20200509105320760.png │ │ │ └── image-20200509113138633.png │ ├── 04 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ └── README.md │ ├── 05 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── 06.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200521140623920.png │ │ │ ├── image-20200521142110423.png │ │ │ ├── image-20200524153542584.png │ │ │ ├── image-20200524153642254.png │ │ │ ├── image-20200524153901884.png │ │ │ ├── image-20200524155447997.png │ │ │ ├── image-20200524162356587.png │ │ │ ├── image-20200524162651959.png │ │ │ ├── image-20200524162916306.png │ │ │ ├── image-20200524163055674.png │ │ │ ├── image-20200524164205504.png │ │ │ ├── image-20200524164328663.png │ │ │ ├── image-20200524185023871.png │ │ │ ├── image-20200524185214938.png │ │ │ ├── image-20200524185421351.png │ │ │ ├── image-20200524185822696.png │ │ │ ├── image-20200524193126939.png │ │ │ ├── image-20200524193651841.png │ │ │ └── image-20200524223336352.png │ ├── 06 │ │ ├── 01.md │ │ ├── 02.md │ │ ├── 03.md │ │ ├── 04.md │ │ ├── 05.md │ │ ├── 06.md │ │ ├── 07.md │ │ ├── 08.md │ │ ├── 09.md │ │ ├── README.md │ │ └── assets │ │ │ ├── image-20200528212208619.png │ │ │ ├── image-20200529213542757.png │ │ │ ├── image-20200529214536307.png │ │ │ ├── image-20200529214753762.png │ │ │ ├── image-20200530122358064.png │ │ │ ├── image-20200530125716379.png │ │ │ ├── image-20200530132505039.png │ │ │ ├── image-20200530184951471.png │ │ │ ├── image-20200530185158299.png │ │ │ ├── image-20200530190512864.png │ │ │ ├── image-20200530190514348.png │ │ │ └── image-20200530190634003.png │ ├── README.md │ └── index.js └── imooc-mysql8 │ ├── 01.md │ ├── 02 │ ├── README.md │ └── assets │ │ ├── image-20200413230903756.png │ │ └── image-20200414221316390.png │ ├── 03 │ ├── README.md │ └── assets │ │ ├── image-20200418213303353.png │ │ ├── image-20200418214759776.png │ │ ├── image-20200418215328833.png │ │ ├── image-20200418215602115.png │ │ ├── image-20200418215912801.png │ │ ├── image-20200418220110463.png │ │ ├── image-20200418220250952.png │ │ └── image-20200419135115513.png │ ├── 04 │ └── README.md │ ├── 05 │ ├── 01.md │ ├── 02.md │ └── README.md │ ├── 06 │ ├── 01.md │ ├── 02.md │ ├── 03.md │ ├── 04.md │ ├── README.md │ └── bak_imc_db_20190128.sql │ ├── 07 │ └── README.md │ ├── 08 │ └── README.md │ ├── 09 │ ├── README.md │ └── assets │ │ └── image-20200513224346202.png │ ├── README.md │ └── index.js ├── package.json └── yarn.lock /.gitattributes: -------------------------------------------------------------------------------- 1 | *.md text 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | build/ 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | .idea 9 | /.idea/ 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | logo 4 | 5 |
6 |
7 | 8 | 所有笔记 → 系列导航 9 | 10 |

11 | 12 | # mysql-tutorial 13 | 14 | mysql 系列教程的笔记 15 | 16 | 在线阅读:https://zq99299.github.io/mysql-tutorial/ 17 | 18 | ## 运行方式 19 | 20 | - 写作预览: 21 | 22 | yarn docs:dev 23 | - 打包发布: 24 | 25 | yarn docs:build 26 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 确保脚本抛出遇到的错误 4 | set -e 5 | 6 | # 删除目录防止构建失败 7 | rm -rf build/.vuepress/dist 8 | 9 | # 生成静态文件 10 | yarn docs:build 11 | 12 | # 进入生成的文件夹 13 | cd build/.vuepress/dist 14 | 15 | # 如果是发布到自定义域名 16 | # echo 'www.example.com' > CNAME 17 | 18 | git init 19 | git add -A 20 | git commit -m 'deploy' 21 | 22 | # 如果发布到 https://.github.io 23 | # git push -f git@github.com:/.github.io.git master 24 | 25 | # 如果发布到 https://.github.io/ 26 | git push -f git@github.com:zq99299/mysql-tutorial.git master:gh-pages 27 | 28 | cd - 29 | -------------------------------------------------------------------------------- /docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | import './styles/fonts/index.styl' -------------------------------------------------------------------------------- /docs/.vuepress/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/.vuepress/public/favicon.ico -------------------------------------------------------------------------------- /docs/.vuepress/public/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/.vuepress/public/hero.png -------------------------------------------------------------------------------- /docs/.vuepress/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MYSQL-TUTORIAL", 3 | "short_name": "MYSQL-TUTORIAL", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#fff", 7 | "description": "mysql 系列教程的笔记", 8 | "icons": [ 9 | { 10 | "src": "mlogo.svg", 11 | "sizes": "48x48", 12 | "type": "image/svg+xml" 13 | }, 14 | { 15 | "src": "mlogo.svg", 16 | "sizes": "100x100", 17 | "type": "image/svg+xml" 18 | }, 19 | { 20 | "src": "mlogo.svg", 21 | "sizes": "200x200", 22 | "type": "image/svg+xml" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /docs/.vuepress/public/mlogo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 31 | 33 | 35 | 37 | 40 | 43 | 45 | 47 | 49 | 50 | -------------------------------------------------------------------------------- /docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Bold-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Bold-Italic.woff2 -------------------------------------------------------------------------------- /docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Bold.woff2 -------------------------------------------------------------------------------- /docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-ExtraBold-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-ExtraBold-Italic.woff2 -------------------------------------------------------------------------------- /docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-ExtraBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-ExtraBold.woff2 -------------------------------------------------------------------------------- /docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Italic.woff2 -------------------------------------------------------------------------------- /docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Medium-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Medium-Italic.woff2 -------------------------------------------------------------------------------- /docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Medium.woff2 -------------------------------------------------------------------------------- /docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/.vuepress/styles/fonts/JetBrainsMono-1.0.3/woff2/JetBrainsMono-Regular.woff2 -------------------------------------------------------------------------------- /docs/.vuepress/styles/fonts/index.styl: -------------------------------------------------------------------------------- 1 | @font-face 2 | { 3 | font-family: "JetBrains Mono"; 4 | src: url(./JetBrainsMono-1.0.3/woff2/JetBrainsMono-Bold.woff2), 5 | url(./JetBrainsMono-1.0.3/woff2/JetBrainsMono-Bold-Italic.woff2), 6 | url(./JetBrainsMono-1.0.3/woff2/JetBrainsMono-ExtraBold.woff2), 7 | url(./JetBrainsMono-1.0.3/woff2/JetBrainsMono-ExtraBold-Italic.woff2), 8 | url(./JetBrainsMono-1.0.3/woff2/JetBrainsMono-Italic.woff2), 9 | url(./JetBrainsMono-1.0.3/woff2/JetBrainsMono-Medium.woff2), 10 | url(./JetBrainsMono-1.0.3/woff2/JetBrainsMono-Medium-Italic.woff2), 11 | url(./JetBrainsMono-1.0.3/woff2/JetBrainsMono-Regular.woff2); 12 | } 13 | 14 | //@font-face 15 | //{ 16 | // font-family: DFPKingGothicGB-Light; 17 | // src: url(./DFPKingGothicGB-Light.ttf); 18 | //} -------------------------------------------------------------------------------- /docs/.vuepress/styles/index.styl: -------------------------------------------------------------------------------- 1 | @media (min-width: 1024px) { 2 | .page { 3 | .theme-default-content, .page-edit, .page-nav { 4 | max-width 740px !important 5 | } 6 | } 7 | } 8 | 9 | /*>=1024的设备*/ 10 | @media (min-width: 1100px) { 11 | .page { 12 | .theme-default-content, .page-edit, .page-nav { 13 | max-width 740px !important 14 | } 15 | } 16 | } 17 | 18 | /*>=1100的设备*/ 19 | @media (min-width: 1280px) { 20 | .page { 21 | .theme-default-content, .page-edit, .page-nav { 22 | max-width 880px !important 23 | } 24 | } 25 | } 26 | 27 | /*>=1280的设备*/ 28 | @media (min-width: 1366px) { 29 | .page { 30 | .theme-default-content, .page-edit, .page-nav { 31 | max-width 966px !important 32 | } 33 | } 34 | } 35 | 36 | @media (min-width: 1440px) { 37 | .page { 38 | .theme-default-content, .page-edit, .page-nav { 39 | max-width 1000px !important 40 | } 41 | } 42 | } 43 | 44 | @media (min-width: 1680px) { 45 | .page { 46 | .theme-default-content, .page-edit, .page-nav { 47 | // max-width 1380px!important 48 | max-width 1000px !important 49 | } 50 | } 51 | } 52 | 53 | @media (min-width: 1920px) { 54 | .page { 55 | .theme-default-content, .page-edit, .page-nav { 56 | // max-width 1420px!important 57 | max-width 1000px !important 58 | } 59 | } 60 | } 61 | 62 | body { 63 | //font-family: "JetBrains Mono", "DFPKingGothicGB-Light", -apple-system, "Hiragino Sans GB", "MicroSoft YaHei", BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; 64 | font-family: "JetBrains Mono", -apple-system, "Hiragino Sans GB", "MicroSoft YaHei", BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; 65 | //color: rgba(0, 0, 0, .65); 66 | color: #333 67 | font-size 16px 68 | line-height: 1.7em; 69 | font-weight: 400; 70 | font-feature-settings: "tnum"; 71 | font-variant: tabular-nums; 72 | } 73 | 74 | .feature p, .page p, ol, ul, li { 75 | word-break: break-all; 76 | text-align: justify; 77 | font-weight: 400; 78 | letter-spacing: 1.6px; 79 | } 80 | 81 | ol, p, ul { 82 | line-height: 1.7em; 83 | } 84 | 85 | code { 86 | font-family: 'JetBrains Mono'; 87 | } 88 | 89 | // 侧边栏 root 间隔变小,字体变小 90 | .sidebar > .sidebar-links > li:not(:first-child) { 91 | margin-top: 0.0rem !important 92 | } 93 | 94 | .sidebar > .sidebar-links > li > a.sidebar-link { 95 | font-size: 1em !important; 96 | line-height: 1.5 !important; 97 | font-weight: normal !important; 98 | } 99 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: mlogo.svg 4 | actionText: 给程序员的 MySQL 必知必会 5 | actionLink: /imooc-mysql8/01.md 6 | features: 7 | - title: 系统学习 8 | details: 零散无基础,会让你很没有安全感,只有系统学习后才能深入了解相关知识点 9 | - title: 边学边练边记 10 | details: 学习过程中一边练习代码一边记录笔记,防止忘记,也在强迫自己记忆了一遍 11 | - title: 坚持学习 12 | details: 每天至少一小时学习时间,能让你不断的进步 13 | footer: MIT Licensed | Copyright © mrcode 14 | --- 15 | 16 | 本笔记仓库是打算系统的学习下 mysql 相关的技术知识 17 | 18 | ## 内容导航 19 | 20 | 建设中 21 | 22 | 分布式事务,有必要去了解下。 23 | ## 规约 24 | 25 | 尽量遵循以下规范。 26 | 27 | - [中文文案排版指北](https://github.com/mzlogin/chinese-copywriting-guidelines) 28 | - [GFM 规范](https://github.github.com/gfm/) 29 | -------------------------------------------------------------------------------- /docs/ali-new-retail/01/README.md: -------------------------------------------------------------------------------- 1 | # 开门见山 2 | 课程内容等介绍 3 | 4 | ## 为什么要学习这门课? 5 | 6 | ![image-20200530200718891](./assets/image-20200530200718891.png) 7 | 8 | 上图是排名前十的新零售,并且阿里收购了多家线下零售,并且率先试水无人超市。 9 | 10 | ![image-20200530200820039](./assets/image-20200530200820039.png) 11 | 12 | 腾讯也投资了很多线下零售企业,也开始搞新零售 13 | 14 | ![image-20200530200935496](./assets/image-20200530200935496.png) 15 | 16 | 苏宁小店、京东便利店等线下零售店已经开了很多家了。新零售垂直领域势头很猛,势必会创造一大批工作岗位。 17 | 18 | 那么来学习新零售数据是怎么设计的就很有必要了。 19 | 20 | ## 适合的人群 21 | 22 | - 程序员:看看良好的数据库是怎么设计的 23 | - 大学生:在校期间设计的数据库比较简单 24 | - 进阶生:适合学完 MySQL 基础的人。 25 | 26 | ## 不是学习创建数据表 27 | 28 | 本课不是教你创建数据表,开发过实际项目的人应该知道,设计一个良好的数据库很难,本课程参考数据易购新零售平台设计一套完整的数据库。**强化开发人员将业务转化成数据库设计的能力** 29 | 30 | 不局限于数据库领域,而是从研发的角度来考虑怎么去设计数据库,以及程序数据库之间是怎么结合的。 31 | 32 | 下面是思维导图,详细介绍了我们要学习的知识 33 | 34 | ![从0到1实战新零售数据库设计与实现](./assets/summary.png) 35 | 36 | ## 学习的收获 37 | 38 | 笔者也是需要了解学习这门可能能收获到那些,这些还是有必要知道,否则你就是在浪费时间。 39 | 40 | - 开发经验很难得:相当于参与了真实项目的数据库设计 41 | - 设计思想要跟上:具备设计完整数据平台的能力 42 | - 特别牛的技术:你可以驾驭新零售数据库混合式集群 43 | 44 | ## 技术储备 45 | 46 | 学习本课程需要有的基础知识 47 | 48 | - 数据库基础 49 | 50 | - 一门编程语言: 51 | 52 | 不会涉及到 web 框架的部分,只会有何数据库交互的部分。也就是说,这里不讲解开发,还是扣题为主,围绕新零售数据库设计来,要了解怎么设计数据库,就需要了解新新零售的相关业务和需求 53 | 54 | -------------------------------------------------------------------------------- /docs/ali-new-retail/01/assets/image-20200530200718891.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/01/assets/image-20200530200718891.png -------------------------------------------------------------------------------- /docs/ali-new-retail/01/assets/image-20200530200820039.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/01/assets/image-20200530200820039.png -------------------------------------------------------------------------------- /docs/ali-new-retail/01/assets/image-20200530200935496.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/01/assets/image-20200530200935496.png -------------------------------------------------------------------------------- /docs/ali-new-retail/01/assets/summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/01/assets/summary.png -------------------------------------------------------------------------------- /docs/ali-new-retail/02/01.md: -------------------------------------------------------------------------------- 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 | 举个例子:比如我的私家车需要做保养,但是线上 APP 是无法做到这个事情的,线上线下业务就结合起来了。在线上选择好保养的项目以及预约到店的时间,线下商家备好货,到时直接就可以做保养了。 36 | 37 | 这就是新零售的一种方式,线上线下结合,既方便又快捷。以互联网+ 的思维去连接工厂、门店、微商,这就是新零售。 38 | 39 | ## 新零售平台构成 40 | 41 | 一般有以下 4 个渠道,除了第一个,其他的都是线上 42 | 43 | ![image-20200530211010903](./assets/image-20200530211010903.png) 44 | 45 | 一般很少有企业全面发展,比如万达从线下往线上发展,淘宝京东是从线上往线下发展。 46 | 47 | 那么渠道的发展顺序一般为(基于成本考虑): 48 | 49 | 1. 小程序 50 | 51 | 企业可以利用小程序起家,小程序的成本是最低的,一般是适合小程序开始,但是小程序的打包体积不能超过 2M,所以不能定义太多的界面。 52 | 53 | 2. APP 54 | 55 | 接下来就可以开发 APP,移动端发展,比如拼多多,发展很壮大了,都没有自己的购物网站。拼多多继续发展壮大的话,后续就很有可能会开发 PC 端产品,附加更多的内容。 56 | 57 | 3. 网站 58 | 59 | 这个时候,用户活跃多,在架构上就能采用数据库集群、消息队列、微服务等等一系列技术。 60 | 61 | 开发一个网站的成本很大,如上面所说的成本起家历程来说,达到这个阶段的话,这些成本企业一般都是可以承受的了。 62 | 63 | 4. 线下门店 64 | 65 | 要用真实的商品、备注货源、要有门店和店员,投入是非常巨大的 66 | 67 | 比如盒马生鲜这种规模的门店,不适合短时间内在全国开很多家,投入巨大,企业承担不起。一家一家来 68 | 69 | ## 本课程与新零售的关系 70 | 71 | 为新零售平台搭建出一个数据库系统。网上有很多讲解电商的课程,由于篇幅原因,基本上都是 **以点带面**,讲解几个模块,草草收尾。 72 | 73 | 本课程虽然讲解的数据库,但是为带领大家搭 **建出一个完整的数据库平台**。我们锁定的目标是: 74 | 75 | - 中小型企业 76 | 77 | 广大中小型企业的新零售需求 78 | 79 | - 日活跃用户 5 万以下 80 | 81 | 指 APP 或 小程序的日活跃用户 82 | 83 | - 最佳的性价比方案 84 | 85 | 通过优化数据表和 sql 语句找到最佳的性价比方案 86 | 87 | - 适用于多平台业务 88 | 89 | 设计出来的数据库,可用在 java、php 等系统上 90 | 91 | ## 业务扩展后的数据库架构变化 92 | 93 | 关键词是:架构、性能、成本、重构,从这几个方面考虑 94 | 95 | 96 | 97 | 随着新零售的发展,从移动端迈向网站,原本的单节点 MySQL 就会遇到瓶颈,这个时候就需要寻找一个新的数据库架构。 98 | 99 | 本课程后半段,在高负载下,如何设计出百万 PV 的数据库平台。提高数据库负载,不仅仅是用上数据库集群那么简单。比如 MySQL 的集群方式就有很多种 100 | 101 | ![image-20200530214432158](./assets/image-20200530214432158.png) 102 | 103 | 高负载带来的问题之一就是大数据量,InnoDB 单表数据超过 2000 万时,性能可能会严重下降。最好的办法就是对数据进行切分,存储到不同的 MySQL 节点上。这里就又牵涉到分布式的相关的东西,节点高可用、读写分离、分布式事物等问题的出现。 104 | 105 | - pxc 集群:每个节点都必须同步接受数据 106 | 107 | - rp 集群:每个节点是异步接受数据的 108 | 109 | 只要一个节点成功接受数据,那么事务就算成功了,如果由于网络原因,读写分离情况下,就可能导致扣款成功,但是订单状态同步失败的问题 110 | 111 | 由于同步方式的不同,他们适合的场景也是不同(规避优缺点);所以: 112 | 113 | - pxc :适合保存强一致性数据 114 | 115 | 如:订单、用户信息等 116 | 117 | - rp:不适合保存强一致性数据 118 | 119 | 比如,用户评价、商品信息等。 120 | 121 | 如果说一项业务既操作了 pxc 又操作了 rp 的数据,这种跨集群的事物就很难实现。包括跨集群联合提取数据,也是很难的。 122 | 123 | 所以:**高负载的数据库设计不是那么好设计的** 124 | 125 | 在本课后半段会讲解如何搭建这种高负载的数据库平台。 126 | -------------------------------------------------------------------------------- /docs/ali-new-retail/02/02.md: -------------------------------------------------------------------------------- 1 | # 前置知识与环境要求 2 | 3 | ## 前置知识 4 | 5 | - 了解 MySQL 基础知识。 6 | - 掌握一种编程语言 7 | 8 | ## 软件环境 9 | 10 | - linux 11 | - docker 12 | - vmware(笔者用 virtual box) 13 | 14 | ## 安装 linux 系统 15 | 16 | [详细的 linux 使用可用参考该文章](https://zq99299.github.io/linux-tutorial/tutorial-basis/03/) 17 | 18 | [关于网络模式](https://zq99299.github.io/note-book/_posts/virtualbox/#%E7%BD%91%E7%BB%9C%E7%AF%87-host-only%EF%BC%88win10%EF%BC%89) 19 | 20 | 本课程建议使用择桥接网络。 21 | 22 | ## 配置 SSH 23 | 24 | [MobaXterm](https://mobaxterm.mobatek.net/),支持如下图的各种连接。很强大 25 | 26 | ![image-20200531205652930](./assets/image-20200531205652930.png) 27 | 28 | ## 虚拟机的克隆与快照 29 | 30 | ![image-20200531210623856](./assets/image-20200531210623856.png) 31 | 32 | VMware 有快照功能,virtual box 的快照功能是备份系统。简单说,我们需要几台 linux 服务器安装 mysql,你可以先装一台,然后克隆几台出来,简单修改下就可以使用了,大量的节省了时间。 33 | 34 | 快照功能:你再瞎搞之前,备份下系统,搞坏了直接还原就行了 35 | 36 | ## Linux 基础知识 37 | 38 | | 目录 | 用途 | 重要性 | 39 | | ---- | -------------------------------- | ------ | 40 | | bin | 存放二进制文件 | 高 | 41 | | dev | 存放硬件文件 | 高 | 42 | | etc | 存放程序的配置文件 | 高 | 43 | | home | 非root用户的目录文件 | 普通 | 44 | | proc | 存放正在运行中的进程文件 | 高 | 45 | | root | root用户目录 | 高 | 46 | | sbin | 存放root用户可以执行的二进制文件 | 高 | 47 | | tmp | 存放系统临时文件 | 低 | 48 | | usr | 存放安装的程序 | 高 | 49 | | var | 存放程序或者系统日志文件 | 高 | 50 | 51 | -------------------------------------------------------------------------------- /docs/ali-new-retail/02/README.md: -------------------------------------------------------------------------------- 1 | # 前置准备 2 | 3 | 本章首先介绍 「新零售」概念,即线上+线下销售模式。 4 | 有别于纯电商,所以业务上既要考虑线下又要考虑线上。 5 | 接下来,需要配置好学习环境,安装 VMware 虚拟机,安装 CentOS 操作系统。 6 | 掌握 VMware 虚拟机的常用管理:创建快照以及创建克隆镜像等等。 7 | 8 | - [新零售业务介绍](./01.md) 9 | - [前置知识与环境要求](./02.md) 10 | -------------------------------------------------------------------------------- /docs/ali-new-retail/02/assets/image-20200530211010903.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/02/assets/image-20200530211010903.png -------------------------------------------------------------------------------- /docs/ali-new-retail/02/assets/image-20200530214432158.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/02/assets/image-20200530214432158.png -------------------------------------------------------------------------------- /docs/ali-new-retail/02/assets/image-20200531205652930.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/02/assets/image-20200531205652930.png -------------------------------------------------------------------------------- /docs/ali-new-retail/02/assets/image-20200531210623856.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/02/assets/image-20200531210623856.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/01.md: -------------------------------------------------------------------------------- 1 | # 安装/配置 MySQL 数据库 2 | 3 | 课程前半部分使用单节点的 MysQL ,所以在 Linux 上直接安装一个 MySQL 即可,后半段使用 docker 来安装 MySQL 集群 4 | 5 | 在笔者的另一个笔记中详细记录了 [如何安装一个 MySQL8](https://zq99299.github.io/mysql-tutorial/imooc-mysql8/02/#%E5%AE%9E%E6%88%98%E7%8E%AF%E5%A2%83%E9%83%A8%E7%BD%B2) 6 | 7 | ## 关闭 SELinux 8 | 9 | ```bash 10 | vi /etc/selinux/config 11 | SELINUX=disabled 12 | ``` 13 | 14 | ## 在线安装MySQL数据库 15 | 16 | * 替换 yum 源 17 | 18 | ```shell 19 | curl -o /etc/yum.repos.d/CentOS-Base.repo mirrors.163.com/.help/CentOS7-Base-163.repo 20 | ``` 21 | 22 | ```shell 23 | yum clean all 24 | yum makecache 25 | ``` 26 | 27 | * 下载 rpm 文件 28 | 29 | ```shell 30 | yum localinstall https://repo.mysql.com//mysql80-community-release-el7-1.noarch.rpm 31 | ``` 32 | 33 | * 安装 MySQL 数据库 34 | 35 | ```shell 36 | yum install mysql-community-server -y 37 | ``` 38 | 39 | ## 本地安装 MySQL 数据库 40 | 41 | * 把本课程 git 工程里共享的 MySQL 本地安装文件上传到 Linux 主机的 `/root/mysql` 目录 42 | 43 | * 执行解压缩 44 | 45 | ```shell 46 | tar xvf mysql-8.0.11-1.el7.x86_64.rpm-bundle.tar 47 | ``` 48 | 49 | * 安装依赖的程序包 50 | 51 | ```shell 52 | yum install perl -y 53 | yum install net-tools -y 54 | ``` 55 | 56 | * 卸载 mariadb 程序包 57 | 58 | ```shell 59 | rpm -qa|grep mariadb 60 | rpm -e mariadb-libs-5.5.60-1.el7_5.x86_64 --nodeps 61 | ``` 62 | 63 | * 安装 MySQL 程序包 64 | 65 | ```shell 66 | rpm -ivh mysql-community-common-8.0.11-1.el7.x86_64.rpm 67 | rpm -ivh mysql-community-libs-8.0.11-1.el7.x86_64.rpm 68 | rpm -ivh mysql-community-client-8.0.11-1.el7.x86_64.rpm 69 | rpm -ivh mysql-community-server-8.0.11-1.el7.x86_64.rpm 70 | ``` 71 | 72 | * 修改 MySQL 目录权限 73 | 74 | ```shell 75 | chmod -R 777 /var/lib/mysql/ 76 | ``` 77 | 78 | * 初始化 MySQL 79 | 80 | ```shell 81 | mysqld --initialize 82 | chmod -R 777 /var/lib/mysql/* 83 | ``` 84 | 85 | 86 | 87 | * 启动 MySQL 88 | 89 | ```shell 90 | service mysql/mysqld start 91 | ``` 92 | 93 | * 查看初始密码 94 | 95 | ```shell 96 | grep 'temporary password' /var/log/mysqld.log 97 | ``` 98 | 99 | * 登陆数据库之后,修改默认密码 100 | 101 | ```sql 102 | mysql -u root -p 103 | alter user user() identified by "abc123456"; 104 | ``` 105 | 106 | * 允许远程使用 root 帐户 107 | 108 | ```sql 109 | UPDATE user SET host = '%' WHERE user ='root'; 110 | FLUSH PRIVILEGES; 111 | ``` 112 | 113 | * 允许远程访问 MySQL 数据库(/etc/my.cnf) 114 | 115 | ```ini 116 | character_set_server = utf8 117 | bind-address = 0.0.0.0 118 | ``` 119 | 120 | * 开启防火墙 3360 端口 121 | 122 | ```shell 123 | firewall-cmd --zone=public --add-port=3306/tcp --permanent 124 | firewall-cmd --reload 125 | ``` 126 | -------------------------------------------------------------------------------- /docs/ali-new-retail/03/04.md: -------------------------------------------------------------------------------- 1 | # 事务机制 2 | 3 | 为什么数据库需要事务机制? 4 | 5 | 平时我们修改文件,一般会先备份一下,再修改。数据库也一样,如果数据的写入直接操作数据文件是非常危险的事情。 6 | 7 | 比如我们 update 语句给员工涨工资,这个时候系统重启了,我们就弄不清那些修改成功了,哪些修改失败了。因为没有原始数据对比,数据发生混乱之后,就特别不好维护。 8 | 9 | 如果想要数据库不直接修改 SQL 文件,就需要引入事务机制了。 10 | 11 | ## 利用日志来实现间接写入 12 | 13 | MySQL 共有 5 种日志,其中只有 **redo** 日志和 **undo** 日志与事务有关。 14 | 15 | ![image-20200602215853158](./assets/image-20200602215853158.png) 16 | 17 | 会将数据复制到 undo 日志中,修改成功后,记录在 redo 日志中,操作没有问题,则把 redo 日志中的数据同步到数据库中。就算系统重启,还有 redo 日志,所以数据一般不会丢失。 18 | 19 | **事务就是利用 undo 和 redo 建立起来的一种操作数据的机制** 20 | 21 | ## 事务机制(Transaction) 22 | 23 | 事务是一个或者多个 SQL 语句组成的整体,要么全部执行成功,要么全都执行失败。 24 | 25 | ## 事务案例 26 | 27 | 把 10 部门中 `MANGER 职位` 的员工调往 20 部门,其他岗位的员工调往 30 部门,然后删除 10 部门。 28 | 29 | MySQL 默认是把每一条 SQL 语句当成一个事务。执行完成后,就让 redo 与数据库同步。 30 | 31 | ![image-20200602220827643](./assets/image-20200602220827643.png) 32 | 33 | 这个需求,需要两个语句,就需要我们手工管理事务了。当 2 条操作都完成后,再同步 redo 数据到数据库中。如果其中一条操作事变了。则从 undo 日志中恢复数据(恢复数据是指:给 undo 和 redo 中的临时数据做一个标识,就不会往数据库中同步数据了) 34 | 35 | ## 事务的 ACID 属性 36 | 37 | ![image-20200602221316208](./assets/image-20200602221316208.png) 38 | 39 | ### 原子性 40 | 41 | 一个事务中的所有操作要么全都成功,要么全都失败。事务执行后不允许停留在某个状态。 42 | 43 | 事务的实现机制:上面讲到过,先拷贝数据(拷贝的是什么数据?)到 undo 中,执行成功后,写入 redo 中,提交事务,把 redo 中的数据同步到数据库中。如果要回滚,则把 undo 与 redo 中的数据标记,则不会同步到数据库中。 44 | 45 | ### 事务的一致性 46 | 47 | 与用户的并发执行有关系。 48 | 49 | 不管在任何给定的时间、并发事务又多少,事务必须保证运行结果的一致性。 50 | 51 | 比如:这个 4 个人的总资产是 2000 元,无论他们怎么转账,同一时间点,他们的总资产始终都满足只有 2000 元。 52 | 53 | ![image-20200602221657199](./assets/image-20200602221657199.png) 54 | 55 | 是如何实现一致性的呢?就是防止读取临时数据,比如: 56 | 57 | 1. A 有 500 元,转账 10 元给 B,事务还未提交 58 | 2. 同时,有人给 A 转账 100 元,并提交了事务,A 的余额为 490 + 100 = 590; 59 | 3. 这个时候,第一步的事务回滚了,不会同步日志数据到数据库中。这个时候 A 的余额就出现问题了 60 | 61 | 保存在日志中的数据,都是由归属的,每个事务之间是隔离的。 62 | 63 | ### 隔离性 64 | 65 | 隔离性要求事务不受其他并发事务的影响,默认情况下 A 事务,只能看到日志中该事务的相关数据。 66 | 67 | ![image-20200602222642797](./assets/image-20200602222642797.png) 68 | 69 | 从机制上看,体现了事务的隔离性,从结果上看体现了一致性 70 | 71 | ### 持久性 72 | 73 | 事务一旦提交(redo 日志同步),结果便是永久性的。即便发生宕机,仍然可以依靠事务日志完成数据的持久化。 74 | 75 | ## 思考题 76 | 77 | 单节点的 MySQL 事务依靠的是 undo 和 redo 日志。那么在数据库集群中,在 A 节点中修改了数据,在 B 节点中添加了新的数据,那么怎么能让这两个节点的事务联合成一个分布式的事务呢? -------------------------------------------------------------------------------- /docs/ali-new-retail/03/README.md: -------------------------------------------------------------------------------- 1 | # 前导知识 2 | 3 | 本章带大家夯实基础: 4 | 5 | - 首先在 CentOS 系统上安装MySQL数据库,做好配置,以及导入练习库。 6 | 7 | - 然后学习 MySQL 核心基础知识,如:看懂ER图、数据库的CRUD操作、事物机制等等。 8 | 9 | 所谓“九层之台,起于累土”,成大事者,都是从基础开始的。... 10 | 11 | - [安装/配置 MySQL 数据库](./01.md) 12 | - [如何看懂 ER 图](./02.md) 13 | - [MySQL 基础 - CRUD](./03.md) 14 | - [事务机制](./04.md) 15 | -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200531215455564.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200531215455564.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200531220337087.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200531220337087.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200531221303648.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200531221303648.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200531221519615.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200531221519615.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200531222154285.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200531222154285.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200531222334973.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200531222334973.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200531222727132.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200531222727132.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200531222858076.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200531222858076.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200601213905083.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200601213905083.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200601214146679.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200601214146679.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200601214239167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200601214239167.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200601214756148.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200601214756148.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200602215853158.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200602215853158.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200602220827643.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200602220827643.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200602221316208.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200602221316208.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200602221657199.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200602221657199.png -------------------------------------------------------------------------------- /docs/ali-new-retail/03/assets/image-20200602222642797.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/03/assets/image-20200602222642797.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/01.md: -------------------------------------------------------------------------------- 1 | # 什么是 SPU/SKU 2 | 3 | 设计数据库时,需要考虑好每一个业务的细节,只有这样设计出来的数据库,才能业务的需求。 4 | 5 | 那么首先就要搞明白一些核心概念。 6 | 7 | ## 本门课程设计什么样的新零售系统? 8 | 9 | ![image-20200602223704818](./assets/image-20200602223704818.png) 10 | 11 | 目前有很多家在做新零售,做的比较好的是苏宁易购,我们就以苏宁易购来作为参考。如果要设计苏宁易购全部的数据库可能要用到上千张表,而且很多业务不适合其他的零售企业,这里提炼了一些通用的业务模块。 12 | 13 | ## 零售系统数据库设计的困难 14 | 15 | 新零售或电商系统的数据库是最难设计的。比如:团队正在开发一个酒店管理系统,是围绕客房展开的,但是每间客房的具体情况也许不同,有的是家庭房、大床房、有的是朝南、朝北,虽然说 **属性值不同**,但是每间客房的 **属性数量是相同的**。这种在设计数据表的时候就非常的简单。 16 | 17 | 再比如说,在线教育系统,里面的商品就是课程,每门课程的属性也是相同的,比如时长、名称、介绍、大纲等等,所以非常好提炼数据表。 18 | 19 | 但是对于新零售或则电商来说,就很难提炼。因为售卖的商品属于不同的种类,商品之间的属性还不同。比如食品有保质期,衣服没有保质期。再比如每种商品都有不同的销售方案,比如 32g 的「小米手机 9」 和 64g 的 「小米手机 9」 是属于两个 **商品**,在设计数据表的时候,需要考虑 **产品** 和 **商品** 之间的对应关系,当用户搜索「小米手机 9 」的时候才能看到各种不同的销售方案。 20 | 21 | 从以上看来,电商的数据库设计难度是真不小。 22 | 23 | ## 产品和商品 24 | 25 | 新零售最难设计的就是 **产品和商品之间的关系** 26 | 27 | ![image-20200602225128185](./assets/image-20200602225128185.png) 28 | 29 | 比如在发布会上发布了 iPhone X,讲解的基本上是他们的共性信息,他们是 **产品**,但是 128G 黑色 iPhone X 才是一个具体的 **商品**。 30 | 31 | 也就是说我们应该设计两张表:**产品表** 和 **商品表** 32 | 33 | ## SPU 34 | 35 | **SPU 全称 Standard Product Unit,是标准产品单位。SPU 描述一个产品的各种特性。** 36 | 37 | - ThinkPad:产品 38 | 39 | 有各种的销售方案,4K 屏、黑色、32G 内存等;商品 40 | 41 | - 小米 9:产品 42 | 43 | 也有各种的销售方案,黑色、128g、红色;商品 44 | 45 | - 技嘉 1060 显卡产品 46 | 47 | 有 2G、4G、6G 版本;商品 48 | 49 | 抛开下面的各种销售方案,他们描述的是共性的东西,所以他们是属于 **产品** 表 50 | 51 | ## 什么时候胡用到 SPU? 52 | 53 | 有可能会决定商品表会重要一些,下订单的时候关联的是商品表。 54 | 55 | 那么产品表有什么作用呢?比如去搜索 Ipad ,出现了如下的商品列表 56 | 57 | ![image-20200602230528749](./assets/image-20200602230528749.png) 58 | 59 | 这些商品列表一般电商平台会这样做: 60 | 61 | 1. 根据搜索的关键字去 **产品表** 检索产品表的主键 ID 62 | 2. 去商品表中搜索 Ipad 产品对应的 **商品中哪个商品方案** 卖得最好 63 | 3. 于是这家店铺销量最高的 ipad **商品** 方案就被检索出来了 64 | 65 | **为什么不去直接搜索商品表中的记录?**因为: 66 | 67 | - 一个产品有多个商品,产品表的数量远远少于商品表; 68 | - 先检索产品表,再检索商品表,这样速度相对来说要快很多 69 | - 再结合索引,就更快了 70 | 71 | ## SKU 72 | 73 | SKU 全称 Stock Keeping Unit ,库存进出计量的单位,SKU 是物理上不可分割的最小存货单元。 74 | 75 | ![image-20200603213714257](./assets/image-20200603213714257.png) 76 | 77 | 如上图,选择的网络类型、机身颜色、套餐类型、存储容量这些组成了一个商品。 78 | 79 | 那么 **库存** 字段是否应该存在 SKU 表中?答案是:看业务,比如这个业务场景中:一个大型连锁店的每个店铺库存都不是一样的,所以一个在 sku 与 库存的交叉表中存在。 80 | 81 | ## SKU 与权重 82 | 83 | - B2B 电商平台,就是类似淘宝这样的电商平台。企业开店,卖东西给客户。 84 | - B2C:类似苏宁易购这样的平台,自己搭建平台,将商品卖给客户。 85 | 86 | 京东是既有 B2B 又有 B2C ,是混合模式。下图是淘宝电商这样的 B2B 模式:淘宝防止店铺卖出商品之后,偷偷修改 SKU 商品信息,于是 **将 SKU 的商品信息与商品的搜索权重绑定** 在一起,只要修改 SKU 商品信息就会影响该商品的搜索权重,甚至严重的话会下架商品。 87 | 88 | ![image-20200603214945548](./assets/image-20200603214945548.png) 89 | 90 | 比如你购买的时候是「进口」奶粉,当你发现被骗的时候,去维权,然后商家连夜修改商品信息去掉了「进口」。这就会造成纠纷。与权重绑定,在很大程度上,能遏制这种操作。 91 | 92 | 并不是所有的信息都会触发权重的变更,比如给这件衣服添加尺码和颜色,因为尺码和颜色是一个新的 sku。 93 | 94 | **对于新零售平台来说**,主要是 B2C 的,所以修改 SKU 对权重的影响不大。但是 B2B 平台,修改 SKU 对商品权重影响很大。 95 | 96 | ## SKU 与参数如何对应? 97 | 98 | ![image-20200603215218640](./assets/image-20200603215218640.png) 99 | 100 | 衣服和手机不是一个品类,他们的参数也不同,在数据表的设计上,就显得很困难。 101 | 102 | ## 这样设计 SKU 表可以吗? 103 | 104 | ![image-20200603215422713](./assets/image-20200603215422713.png) 105 | 106 | 将所有的参数字段都统计出来,像淘宝这样的平台,那么多的品类,参数字段可能需要几万个。这样设计肯定是不行的 107 | 108 | ## 如何设计品类参数? 109 | 110 | ![image-20200603215726550](./assets/image-20200603215726550.png) 111 | 112 | 如图,在参数表中包含了一个品类的所有参数,增加或删除参数,值需要修改参数表的一行数据就可以了。 113 | 114 | ## 参数与 SKU 的关系 115 | 116 | ![image-20200603215918744](./assets/image-20200603215918744.png) 117 | 118 | 一个产品只属于一个品类。一个产品有多个商品。这 4 张表可以关联出一个 SKU 商品的所有参数 -------------------------------------------------------------------------------- /docs/ali-new-retail/04/07.md: -------------------------------------------------------------------------------- 1 | # 设计购物卷表 2 | 3 | 购物的时候可以使用购物卷表,先设计。 4 | 5 | ## 购物卷的使用规则 6 | 7 | ![image-20200606171635552](./assets/image-20200606171635552.png) 8 | 9 | 从上可以看到如下信息: 10 | 11 | - 购物卷有使用期限,而且一个订单只可以用一张购物卷 12 | 13 | - 购物卷与客户记录关联 14 | 15 | 需要客户自己领取,而且客户可以领取多张不同的购物卷 16 | 17 | 所以需要两张表。 18 | 19 | ## 创建购物卷表 20 | 21 | ![image-20200606171848575](./assets/image-20200606171848575.png) 22 | 23 | - denomination:购物卷金额 24 | - condition:超过多少金额才能使用购物卷 25 | - start_date 和 end_date :使用期限,注意:只有日期,没有时间 26 | - max_num:购物卷最多发放多少张。没有值则不限制。 27 | 28 | ```sql 29 | create table t_voucher 30 | ( 31 | id int unsigned primary key auto_increment comment '主键', 32 | deno decimal(10, 2) unsigned not null comment '面值', 33 | `condition` decimal(10, 2) unsigned not null comment '订单满多少钱可以使用', 34 | start_date date comment '起始日期', 35 | end_date date comment '截止日期', 36 | max_num int comment '购物卷发放最大数量' 37 | ) comment '购物卷表'; 38 | 39 | ``` 40 | 41 | 插入一些测试数据 42 | 43 | ```sql 44 | INSERT INTO neti.t_voucher (id, deno, `condition`, start_date, end_date, max_num) VALUES (1, 50.00, 1000.00, '2020-06-06', '2020-06-25', 1000); 45 | INSERT INTO neti.t_voucher (id, deno, `condition`, start_date, end_date, max_num) VALUES (2, 20.00, 500.00, '2020-06-06', '2020-06-25', null); 46 | ``` 47 | 48 | 49 | 50 | ## 客户关联购物卷表 51 | 52 | ![image-20200606172417791](./assets/image-20200606172417791.png) 53 | 54 | 该表主键不是符合主键,原因是:一个人可以领取多张同样的购物卷(这个看自己的业务),要购买一堆东西,结果用户发现可以拆成 2 单,分别用一张购物卷,更划算。 55 | 56 | ```sql 57 | create table t_voucher_customer 58 | ( 59 | id int unsigned primary key auto_increment comment '主键', 60 | voucher_id int unsigned not null comment '购物卷ID', 61 | customer int unsigned not null comment '客户ID' 62 | ) comment '客户关联购物卷表'; 63 | ``` 64 | 65 | 插入一些测试数据 66 | 67 | ```sql 68 | INSERT INTO neti.t_voucher_customer (id, voucher_id, customer) VALUES (1, 1, 1); 69 | INSERT INTO neti.t_voucher_customer (id, voucher_id, customer) VALUES (2, 1, 1); 70 | INSERT INTO neti.t_voucher_customer (id, voucher_id, customer) VALUES (3, 1, 1); 71 | INSERT INTO neti.t_voucher_customer (id, voucher_id, customer) VALUES (4, 2, 1); 72 | INSERT INTO neti.t_voucher_customer (id, voucher_id, customer) VALUES (5, 2, 1); 73 | ``` 74 | 75 | 对于购物卷,也有很多不同的业务场景,新零售做的是 B2C 的业务,没有第三方商铺,在线上和线下都可以使用。而 B2B 则是,对应商品的购物卷只能在对应的商品内使用。 76 | 77 | 对于京东这种混合 B2C 和 B2B 的业务场景,更复杂 -------------------------------------------------------------------------------- /docs/ali-new-retail/04/08.md: -------------------------------------------------------------------------------- 1 | # 设计订单表 2 | 3 | 一张订单中可以包含多个商品记录,可不可以用 JSON 存储这些商品信息?不适合 4 | 5 | 因为 :MySQL 5.7+ 引入的 JSON 字段适合存储数据,**不适合检索数据**。这里存储的数据只是用来页面展示,而 **不用来做搜索条件**,在前面设计的表中,很少对字符串的字段做索引。也是如此。 6 | 7 | 所以需要两张表来保存订单数据 8 | 9 | ## 创建订单表 10 | 11 | ![image-20200606204651069](./assets/image-20200606204651069.png) 12 | 13 | - code:订单流水号;规则可自定义 14 | 15 | 流水号尾部以字母 A 结尾表示液体,B 结尾表示易碎品,等。还可以包含订单的日期、和时间,消费小票打印出来后,阅读流水号可以知道是哪一类的商品、什么时候生成的订单、是否加急发货等。这些规则由业务人员去制定。 16 | 17 | - type:订单类型 18 | 19 | 如为 1:表示线下销售商品,为 2 为线上销售的商品 20 | 21 | - shop_id:店铺ID 22 | 23 | 如果线上卖出的,可以为空 24 | 25 | - customer_id:客户ID 26 | 27 | 主要用来关联会员等级等。如果用户在线下购买的商品,不是会员可以为空 28 | 29 | - amount:订单的总价格 30 | 31 | - payment_type:订单的支付类型 32 | 33 | 比如是借记卡付款、信用卡、微信支付、现今支付等等 34 | 35 | - status:订单状态 36 | 37 | 如:未付款、已付款、已发货、已签收等 38 | 39 | - postage:邮费 40 | 41 | - weight:订单总重量,单位为 克 42 | 43 | 比如京东超过多少重量加收运费,数据库这里不用管这个逻辑,这个是程序的问题。这里只需要留出字段 44 | 45 | - voucher_id:购物卷ID 46 | 47 | 通常情况下,一个订单只能使用一张购物卷。 48 | 49 | - create_time:订单创建的时间 50 | 51 | 字段前面有菱形标识的,这里是需要创建索引的。 52 | 53 | ```sql 54 | create table t_order 55 | ( 56 | id int unsigned primary key auto_increment comment '主键', 57 | `code` varchar(200) not null comment '流水号', 58 | type tinyint unsigned not null comment '订单类型:1实体销售,2网络销售', 59 | shop_id int unsigned comment '零售店ID', 60 | customer_id int unsigned comment '会员ID', 61 | amount decimal(10, 2) unsigned not null comment '总金额', 62 | payment_type tinyint unsigned not null comment '支付方式:1借记卡、2信用卡、3微信、4支付宝、5现金', 63 | `status` tinyint unsigned not null comment '状态:1未付款、2已付款、3已发货、4已签收', 64 | postage decimal(10, 2) unsigned comment '邮费', 65 | weight int unsigned comment '重量:单位克', 66 | voucher_id int unsigned comment '购物券ID', 67 | create_time timestamp not null default now(), 68 | index idx_code (`code`), 69 | index idx_customer_id (customer_id), 70 | index idx_status (`status`), 71 | index idx_create_time (create_time), 72 | index idx_type (type), 73 | index idx_shop_id (shop_id), 74 | unique unq_code (`code`) 75 | ) comment '订单表'; 76 | ``` 77 | 78 | 插入一些测试数据 79 | 80 | ```sql 81 | INSERT INTO neti.t_order (id, code, type, shop_id, customer_id, amount, payment_type, status, postage, weight, voucher_id, create_time) VALUES (1, 'CX0000000120160522', 1, 3, 1, 2999.00, 5, 2, null, null, null, '2020-05-19 23:14:10'); 82 | ``` 83 | 84 | 流水号按你的实际业务,这里不是强制的 85 | 86 | ## 订单详情表 87 | 88 | ![image-20200606210946028](./assets/image-20200606210946028.png) 89 | 90 | 此表将订单与商品关联在一起的关联表。 91 | 92 | - order_id 和 sku_id :复合主键 93 | 94 | 一个订单中不会出现两个相同的商品,可以用数量去记录多件 95 | 96 | - price:商品原价 97 | 98 | - actual_price:购买商品的实际价格 99 | 100 | - num:购买商品的实际数量 101 | 102 | ```sql 103 | create table t_order_detail 104 | ( 105 | order_id int unsigned not null comment '订单ID', 106 | sku_id int unsigned not null comment '商品ID', 107 | price decimal(10, 2) unsigned not null comment '原价格', 108 | actual_price decimal(10, 2) unsigned not null comment '实际购买价格', 109 | num int unsigned not null comment '购买数量', 110 | primary key (order_id, sku_id) 111 | ) comment '订单详情表' 112 | ``` 113 | 114 | 插入一点测试数据 115 | 116 | ```sql 117 | INSERT INTO neti.t_order_detail (order_id, sku_id, price, actual_price, num) VALUES (1, 3, 2999.00, 2999.00, 1); 118 | ``` 119 | 120 | -------------------------------------------------------------------------------- /docs/ali-new-retail/04/11.md: -------------------------------------------------------------------------------- 1 | # 设计评价表 2 | 3 | ![image-20200607122626332](./assets/image-20200607122626332.png) 4 | 5 | - order_id:订单编号 6 | - sku_id:商品编号 7 | - img:卖家晒的图片 8 | - rating:评分,1 到 5 星 9 | - comment:文字评价 10 | 11 | order_id 与 sku_id 都不是唯一性约束,设计目的的可用给每个商品评价。 12 | 13 | ```sql 14 | create table t_rating 15 | ( 16 | id int unsigned primary key auto_increment not null comment '主键', 17 | order_id int unsigned not null comment '订单ID', 18 | sku_id int unsigned not null comment '商品ID', 19 | img json comment '买家嗮图', 20 | rating tinyint unsigned not null comment '评分', 21 | `comment` varchar(200) comment '评论', 22 | create_time timestamp not null default now() comment '添加时间', 23 | index idx_order_id (order_id), 24 | index idx_sku_id (sku_id), 25 | index idx_create_time (create_time) 26 | ) comment ='评价表'; 27 | ``` 28 | 29 | 插入一些测试数据 30 | 31 | ```sql 32 | INSERT INTO neti.t_rating (id, order_id, sku_id, img, rating, comment, create_time) VALUES (1, 2, 3, '["http://192.22/1.jpg"]', 5, '很好用,非常好', '2020-05-20 09:01:08'); 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /docs/ali-new-retail/04/12.md: -------------------------------------------------------------------------------- 1 | # 设计供货商数据表 2 | 3 | 本章和下一章,将新零售的进销存功能相关表设计下,因为涉及到进货,就需要用到供货商和商品入库表表 4 | 5 | ![image-20200607123603057](./assets/image-20200607123603057.png) 6 | 7 | supplier:供货商表 8 | 9 | - code:供货商编号 10 | 11 | - name:供货商名称 12 | 13 | - type:供货商类型:如厂家、代理等 14 | 15 | - link_man:联系人名称 16 | 17 | - tel:电话 18 | 19 | - bank_name:开户银行名称 20 | 21 | 可以为空,由于供货商类型不同,比如农民,没有企业开户行 22 | 23 | - bank_account:开户银行账户 24 | 25 | - address:供货商地址 26 | 27 | - status:供货商状态 28 | 29 | supplier_sku:供货商与商品关联表 30 | 31 | ```sql 32 | create table t_supplier 33 | ( 34 | id int unsigned primary key auto_increment not null comment '主键', 35 | `code` varchar(200) not null comment '供货商编号', 36 | `name` varchar(200) not null comment '供货商名称', 37 | `type` tinyint unsigned not null comment '供货商类型:1厂家、2代理商、3个人', 38 | link_man varchar(20) not null comment '联系人', 39 | tel varchar(20) not null comment '联系电话', 40 | bank_name varchar(200) comment '开户银行名称', 41 | bank_account varchar(200) comment '开户银行账户', 42 | address varchar(200) not null comment '联系地址', 43 | `status` tinyint unsigned not null comment '状态:1可用、2不可用', 44 | index idx_code (`code`), 45 | index idx_type (`type`), 46 | index idx_status (`status`), 47 | unique unq_code (`code`) 48 | ) comment ='供货商表'; 49 | 50 | create table t_supplier_sku 51 | ( 52 | supplier_id int unsigned not null comment '供货商ID', 53 | sku_id int unsigned not null comment '商品ID', 54 | primary key (supplier_id, sku_id) 55 | ) comment ='供货商与商品关联表'; 56 | ``` 57 | 58 | 插入一些测试数据 59 | 60 | ```sql 61 | INSERT INTO neti.t_supplier (id, code, name, type, link_man, tel, bank_name, bank_account, address, status) VALUES (1, '2394125', 'A供货商', 1, '李强', '13399999999', '', null, '辽宁省高兴区121号', 1); 62 | 63 | INSERT INTO neti.t_supplier_sku (supplier_id, sku_id) VALUES (1, 1); 64 | INSERT INTO neti.t_supplier_sku (supplier_id, sku_id) VALUES (1, 2); 65 | INSERT INTO neti.t_supplier_sku (supplier_id, sku_id) VALUES (1, 3); 66 | ``` 67 | 68 | -------------------------------------------------------------------------------- /docs/ali-new-retail/04/14.md: -------------------------------------------------------------------------------- 1 | # 总结 2 | 3 | 本章重点知识 4 | 5 | | 序号 | 知识点 | 重要性 | 6 | | ---- | -------------------------------- | ------ | 7 | | 1 | 掌握产品、商品之间的关系 | 重要 | 8 | | 2 | 掌握品类与参数之间的关系 | 重要 | 9 | | 3 | 掌握客户、订单、购物卷相关数据表 | 重要 | 10 | | 4 | 掌握进销存相关数据表的设计 | 普通 | 11 | 12 | 这里以苏宁易购新零售为例子设计了一个小型的新零售数据库,可以根据实际的业务对表字段做修改 -------------------------------------------------------------------------------- /docs/ali-new-retail/04/README.md: -------------------------------------------------------------------------------- 1 | # 新零售数据结构设计 2 | 3 | 本章结合新零售业务需求,以苏宁易购为蓝本,设计新零售的数据库平台,将开启你对数据库认识的新篇章,理解业务需求基础上,把业务拆分成一张张关系表。 4 | 5 | 例如商品、产品、门类、品类、订单、仓库、库存、顾客、收货地址、购物券等。... 6 | 7 | - [什么是 SPU/SKU](./01.md) 8 | - [设计品类表和参数表](./02.md) 9 | - [设计品牌和分类关系表](./03.md) 10 | - [设计产品表和商品表](./04.md) 11 | - [如何设计商品的库存?](./05.md) 12 | - [设计客户表](./06.md) 13 | - [设计购物卷表](./07.md) 14 | - [设计订单表](./08.md) 15 | - [设计员工与用户表](./09.md) 16 | - [设计快递表和退货表](./10.md) 17 | - [设计评价表](./11.md) 18 | - [设计供货商数据表](./12.md) 19 | - [设计采购与入库数据表](./13.md) 20 | - [总结](./14.md) 21 | -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200602223704818.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200602223704818.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200602225128185.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200602225128185.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200602230528749.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200602230528749.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200603213714257.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200603213714257.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200603214945548.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200603214945548.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200603215218640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200603215218640.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200603215422713.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200603215422713.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200603215726550.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200603215726550.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200603215918744.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200603215918744.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200603221242071.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200603221242071.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200603222446159.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200603222446159.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200603225440768.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200603225440768.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200603230456735.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200603230456735.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200604210829879.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200604210829879.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200604211023017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200604211023017.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200604211722057.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200604211722057.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200604211943017.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200604211943017.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200604212817714.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200604212817714.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200604213521317.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200604213521317.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200604215701973.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200604215701973.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200604220358810.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200604220358810.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200604221848513.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200604221848513.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200604222316161.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200604222316161.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606152330688.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606152330688.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606152633397.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606152633397.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606153031009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606153031009.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606153653899.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606153653899.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606154802659.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606154802659.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606155611696.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606155611696.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606163539733.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606163539733.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606163923678.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606163923678.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606164933171.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606164933171.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606171635552.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606171635552.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606171848575.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606171848575.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606172417791.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606172417791.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606204651069.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606204651069.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606210946028.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606210946028.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606213335284.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606213335284.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200606213452640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200606213452640.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200607100906653.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200607100906653.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200607102720626.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200607102720626.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200607103831302.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200607103831302.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200607122626332.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200607122626332.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200607123603057.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200607123603057.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200607125625266.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200607125625266.png -------------------------------------------------------------------------------- /docs/ali-new-retail/04/assets/image-20200607125645561.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/04/assets/image-20200607125645561.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/01.md: -------------------------------------------------------------------------------- 1 | # 主键用数字还是 UUID? 2 | 3 | ## 什么是 UUID? 4 | 5 | UUID 是通用唯一识别码的缩写,其目的是让分布式系统中的所有元素,都能具有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。 6 | 7 | 下面是 UUID 的组成 8 | 9 | ![image-20200607140909217](./assets/image-20200607140909217.png) 10 | 11 | ```sql 12 | -- 数据库中使用 uuid 函数 13 | select uuid(); 14 | ``` 15 | 16 | ## 为什么有人想要使用 UUID? 17 | 18 | 在数据库集群中,为了避免每个 MySQL 各自生成的主键产生重复,所以有人考虑采用 UUID 方式 19 | 20 | ![image-20200607141059856](./assets/image-20200607141059856.png) 21 | 22 | 如果采用自增模式,会出现全局 ID 冲突。 23 | 24 | ## UUID 主键的好处 25 | 26 | - 分布式生成主键,减低了全局节点的压力,使得主键生成速度更快 27 | 28 | - 主键全局唯一 29 | 30 | - 跨服务器合并数据很方便 31 | 32 | 从第 2 条中派生出来的。由于 ID 唯一,所以整合方便。 33 | 34 | ## UUID 主键的缺点 35 | 36 | - 浪费存储空间 37 | 38 | UUID 占用 16 个字节,比 4 字节的 int 类型和 8 字节的 bigint 类型更占用存储空间。 39 | 40 | 在聚簇索引上,非主键列都会携带主键值,所以更占用空间 41 | 42 | - 查询速度慢 43 | 44 | UUID 是字符串,查询速度慢; 45 | 46 | 这个往深了说,还是和 B-Tree 有关。 47 | 48 | - 数据写入随机性很大 49 | 50 | UUID 不是顺序增长,作为主键,数据写入 IO 随机性很大; 51 | 52 | 这个往深了说,还是和 B-Tree 和存储机制有关。 53 | 54 | ## 主键自动增长的有点 55 | 56 | - 占用空间少:int 和 BIGINT 类型占用存储空间少 57 | - 检索速度快:MySQL 检索数字类型速度远快于字符串 58 | - IO 写入连续性好:由于主键是顺序增长的,写入连续性好 59 | 60 | ## 分布式环境下的主键自动增长 61 | 62 | 有人想要使用 UUID 作为主键,就是在分布式环境下主键会全局冲突的问题。 63 | 64 | ![image-20200607141942571](./assets/image-20200607141942571.png) 65 | 66 | 比如 MyCat 中间件,就可以生成全局连续的主键值。 67 | 68 | ## 总结 69 | 70 | 无论什么场合,都不推荐使用 UUID 作为数据表的主键; 71 | 72 | 分布式环境下有类似 MyCat 这样的中间件来生成全局的顺序主键 -------------------------------------------------------------------------------- /docs/ali-new-retail/05/02.md: -------------------------------------------------------------------------------- 1 | # 在线修改表结构 2 | 3 | 场景:对一个正在运营的电商网站修改表结构 4 | 5 | ## 在线修改表结构必须慎重 6 | 7 | - 在业务系统 **运行** 过程中随意删改字段,会 **造成重大事故**。 8 | 9 | - 常规的做法是:**业务停机**,再 **维护表结构** 10 | 11 | 比如:12306 凌晨 0 点到早上 7 点是停机维护 12 | 13 | - 如果是不影响正常业务的表结构是允许在线修改的。 14 | 15 | 比如:int 类型不够用了,要缓存 bigint、有唯一性约束,要去掉。这不会影响线上的正在执行的数据 16 | 17 | ## alter table 修改表结构的弊端 18 | 19 | - 表级锁 20 | 21 | 修改表结构会锁表,因此在修改表结构时,影响表的写入操作; 22 | 23 | 数据越多,锁表时间越长。 24 | 25 | - 修改失败,还原表结构,耗时长 26 | 27 | 如果修改表结果失败,必须还原表结构,所以耗时更长; 28 | 29 | 比如:添加一个唯一性约束,结果发现很多数据有控制,无法添加进来了,这个时候就只能还原表结构 30 | 31 | - 大数据表记录多,修改表结构锁表时间很久 32 | 33 | ## 使用 PerconaTookit 工具 34 | 35 | 由于 alter table 线上修改表结构有诸多弊端,但是 PerconaTookit 提供了一个开源的线上修改表结构的工具。 36 | 37 | 其中一个名为 **pt-online-schema-change** 的工具可以完成在线修改表结构。 38 | 39 | ## 在线修改表结构的原理 40 | 41 | **pt-online-schema-change** 是如何做到不锁表修改表结构的? 42 | 43 | 我要修改 order 表的结构, **pt-online-schema-change** 会这样做: 44 | 45 | 1. 复制一份 order 表结构 46 | 47 | 2. 在这个新表的修改表结构 48 | 49 | 3. 同步执行数据拷贝 50 | 51 | 修改完成之后,会在原来表上增加触发器,新的操作数据增删改查都会同步到新的表中, 52 | 53 | 同时会把原来表的数据拷贝到新表中。 54 | 55 | 当数据拷贝完之后,且 **原表没有新的数据写入时**,把原表删除,把新表名称修改为原表名称 56 | 57 | 笔者其实很疑惑的是:它这个表数据同步原理,这里说得不够清楚,说得很模糊。在同步时修改了原来表的数据怎么办?原表的数据都还没有同步完成。 58 | 59 | ## 安装 PerconaTookit 依赖包 60 | 61 | 该依赖包与 MySQL 8 有冲突?不要安装在同一台上面? 62 | 63 | 安装第三方依赖包 64 | 65 | ```bash 66 | yum install -y perl-DBI 67 | yum install -y perl-DBD-mysql 68 | yum install -y perl-IO-Socket-SSL 69 | yum install -y perl-Digest-MD5 70 | yum install -y perl-TermReadKey 71 | ``` 72 | 73 | 安装 PerconaTookit 工具 74 | 75 | ```sql 76 | rpm -ivh percona-toolkit-3.0.13-1.el7.x86_64.rpm 77 | rpm -ivh percona-toolkit-debuginfo-3.0.13-1.el7.x86_64.rpm 78 | ``` 79 | 80 | ## **pt-online-schema-change** 用法 81 | 82 | ```bash 83 | pt-online-schema-change OPTIONS DSN 84 | 85 | 参数有: 86 | 87 | --host: 地址 88 | --user: 用户名 89 | --password:密码 90 | --port:端口号 91 | D:逻辑库 92 | t:数据表 93 | --alter:修改语句 94 | --execute:执行修改 95 | --dry-run:测试执行 96 | --print:打印过程 97 | ``` 98 | 99 | 实践 100 | 101 | 在执行前还需要修改下密码认证方式,因为该工具不支持 MySQL8 新的默认认证方式,将认证方式改成低版本的方式 102 | 103 | ```sql 104 | alter user 'root'@'%' identified by 'password' password expire never; 105 | alter user 'root'@'%' identified with mysql_native_password by '123456'; 106 | ``` 107 | 108 | ```sql 109 | -- 把客户收货地址表中的 name 字段改成 varchar(20) 110 | 111 | pt-online-schema-change --host=192.168.56.101 --port=3306 --user=root --password=123456 --alter "modify name varchar(20) not null comment '收货人'" D=neti,t=t_customer_address --print --execute 112 | 113 | -- 笔者这里执行完成之后,报错了 114 | There is an error in MySQL that makes the server to die when trying to rename a table with FKs. See https://bugs.mysql.com/bug.php?id=96145 115 | Since pt-online-schema change needs to rename the old <-> new tables as the final step, and the requested table has FKs, it cannot be executed under the current MySQL version 116 | 117 | 难道死是 MySQL 版本的问题?还是工具版本的问题? 这个就不清楚了。 118 | ``` 119 | 120 | 下面是执行成功的截图 121 | 122 | ![image-20200607152047353](./assets/image-20200607152047353.png) 123 | 124 | 也可以看到的确是有一些触发器的操作。 125 | 126 | -------------------------------------------------------------------------------- /docs/ali-new-retail/05/03.md: -------------------------------------------------------------------------------- 1 | # 订单和流水号的区别 2 | 3 | - 订单号:是订单的唯一编号,经常用来做检索,所以应当是数字类型的主键 4 | - 流水号:一般是打印在购物单据上的字符串,便于阅读,但是不用做查询 5 | 6 | 来看看一个流水号的规则 7 | 8 | ![image-20200607173145363](./assets/image-20200607173145363.png) 9 | 10 | 品类编号:如果一个订单中有多个品类,你可以取最贵的那一个;上图是一个 28 位的流水号。 11 | 12 | 至于流水号的组成规则,根据自身的业务需求来制定; 13 | 14 | 下面是用 java 代码生成的一个示例 15 | 16 | ```java 17 | @Test 18 | public void fun1() { 19 | String orderCode = createOrderCode("S", "123456", "10001", "200520"); 20 | // S123456100012005204676137770 21 | System.out.println(orderCode); 22 | } 23 | 24 | public static String createOrderCode(String type, 25 | String organizationId, 26 | String spgId, 27 | String date) { 28 | StringBuilder builder = new StringBuilder(); 29 | builder.append(type); 30 | builder.append(organizationId); 31 | builder.append(spgId); 32 | builder.append(date); 33 | // 主要是这个生成随机数的 API。 jdk8 中的方式 34 | String random = ThreadLocalRandom.current() 35 | .ints(0, 9) 36 | .limit(10) 37 | .mapToObj(Integer::toString) 38 | .collect(Collectors.joining("")); 39 | builder.append(random); 40 | return builder.toString(); 41 | } 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /docs/ali-new-retail/05/04.md: -------------------------------------------------------------------------------- 1 | # 逻辑删除还是物理删除 2 | 3 | 一般情况下,公司会要求只能逻辑删除不能物理删除。那么这是为什么呢? 4 | 5 | ## 物理删除 6 | 7 | 使用 delete、truncate、drop 语句删除数据。就是把数据从硬盘中删除,可释放存储空间,缩小数据表的体积。 8 | 9 | ### 代价:恢复数据困难 10 | 11 | 那么物理删除是有代价的(如果想要恢复数据的话): 12 | 13 | - 恢复数据难度大 14 | - 还要停掉数据库,对业务系统影响巨大 15 | 16 | 第一种恢复数据的方法:利用 binlog 日志 17 | 18 | 大概的恢复流程如下: 19 | 20 | ![image-20200607180027818](./assets/image-20200607180027818.png) 21 | 22 | 1. 程序分析 binlog 日志,找出误删除的日志,踢出掉该语句 23 | 2. 然后把日志里的数据重新执行一遍 24 | 25 | 更多的细节视频中也没有说清楚,要使用这个方法,需要你对 binlog 日志比较熟悉。 26 | 27 | 第二种恢复数据的方法:给数据库做一个颜时同步节点 28 | 29 | - 给数据库配置一个同步数据的数据库 30 | - 同步时间,要延时:比如 1 小时同步一次 31 | - 当出现问题的时候,只要在这个延时时间内,都还可以恢复出一定的数据 32 | 33 | ### 代价:主键不连续 34 | 35 | 物理删除会造成主键的不连续,导致分页查询变慢; 36 | 37 | ```sql 38 | select ... from ... limit 1000,20; 39 | ``` 40 | 41 | 从 1000 条记录开始往后取 20 条数据。它需要计数跳过的行,越往后计数越多,就越慢。需要一个方法来加快查询。 42 | 43 | 于是就想到了如下方法:通过主键字段分页的方式 44 | 45 | ```sql 46 | select ... from ... where id>1000 and id <= 1020; 47 | ``` 48 | 49 | 主键是带索引的,条件过滤可以快速的过滤掉很多数据。(这方面要去了解 b-tree 索引的原理,你才能明白)。 50 | 51 | 如果采用 **物理删除**,那么将导致数据不连续了,无法通过这种方式跳过 N 条数据。 52 | 53 | 在后续的课程中会讲解分页的优化。 54 | 55 | ## 什么数据不适合物理删除? 56 | 57 | **核心业务表 **的数据不建议做物理删除**,只做状态变更**。比如订单作废、账户禁用、优惠卷作废等等。 58 | 59 | 这种做法其实就是 **逻辑删除** 60 | 61 | 当数据量大的时候,想要缩小数据表的体积,可以将逻辑删除的数据转移到历史表。 62 | 63 | **注意:** 这里说的转移记录,和前面的分页方案无关了,不要考虑前面那个分页场景了。 64 | 65 | ## 逻辑删除 66 | 67 | 可以给数据添加一个字段,如 `is_deleted` ,用该字段标记该数据已经逻辑删除,查询的时候跳过这些数据。 68 | 69 | 对于迁移历史记录表,也是有必要添加该 `is_deleted` 字段的,例如:我们可以在系统负载较少的时候(如后半夜访问较少的时候),通过定时任务将逻辑删除的数据,迁移到历史表。 70 | 71 | ## 改造我们的核心业务表 72 | 73 | 之前创建的数据表,我们都没有设置这个逻辑删除的字段。这里要去改造一下。由于表众多,这里演示其中一个表的「逻辑删除」和「历史表」的制作 74 | 75 | ```sql 76 | -- 克隆表结构:创建历史表 77 | crete table t_user_history like t_user; 78 | 79 | -- 添加删除字段:历史表中不加该字段,因为都是删除的数据 80 | alter table t_user 81 | add column is_deleted boolean not null default 0 comment '逻辑删除'; 82 | ``` 83 | 84 | -------------------------------------------------------------------------------- /docs/ali-new-retail/05/05.md: -------------------------------------------------------------------------------- 1 | # 千万记录,如何快速分页 2 | 3 | 首先先来看下面几个语句的查询时间 4 | 5 | ```sql 6 | select id,name from t_test limit 100,100; 7 | select id,name from t_test limit 10000,100; 8 | select id,name from t_test limit 1000000,100; 9 | select id,name from t_test limit 5000000,100; 10 | ``` 11 | 12 | 那么先创建测试数据表和测试数据 13 | 14 | 创建测试表 15 | 16 | ```sql 17 | create table t_test 18 | ( 19 | id int unsigned primary key not null, 20 | `name` varchar(200) not null 21 | ) 22 | ``` 23 | 24 | 插入测试数据 25 | 26 | ```java 27 | @Test 28 | public void fun2() { 29 | try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("/Users/mrcode/Desktop/test.sql"))) { 30 | for (int i = 1; i <= 10000000; i++) { 31 | // writer.append("insert into t_test(id,`name`) values (" + i + ",'" + UUID.randomUUID().toString() + "');\n"); 32 | // 这是利用工具导入,只输出列值 33 | writer.append(i + "," + UUID.randomUUID().toString() + "\n"); 34 | } 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | 40 | ``` 41 | 42 | 编写了一个产生 1000 万行的随机数据,通过工具导入;笔者测试过以下两种方式: 43 | 44 | - 生成 insert into 语句,通过 navicat 执行 sql 文件导入 45 | 46 | 耗时 30 分钟,结果还把数据库搞死了。 47 | 48 | 原因是:使用这种方式是带事务执行的,特别慢 49 | 50 | - 生成数据,用 DataGrip 导入 51 | 52 | 只用了 4 分钟。这种方式是不带事务的带入。 53 | 54 | 看看查询时间信息 55 | 56 | ```sql 57 | neti> select id,name from t_test limit 100,100 58 | [2020-06-07 20:09:52] 100 rows retrieved starting from 1 in 37 ms (execution: 9 ms, fetching: 28 ms) 59 | neti> select id,name from t_test limit 10000,100 60 | [2020-06-07 20:10:06] 100 rows retrieved starting from 1 in 48 ms (execution: 15 ms, fetching: 33 ms) 61 | neti> select id,name from t_test limit 1000000,100 62 | [2020-06-07 20:10:15] 100 rows retrieved starting from 1 in 362 ms (execution: 336 ms, fetching: 26 ms) 63 | neti> select id,name from t_test limit 5000000,100 64 | [2020-06-07 20:10:21] 100 rows retrieved starting from 1 in 1 s 244 ms (execution: 1 s 220 ms, fetching: 24 ms) 65 | neti> select id,name from t_test limit 9000000,100 66 | [2020-06-07 20:11:44] 100 rows retrieved starting from 1 in 2 s 247 ms (execution: 2 s 221 ms, fetching: 26 ms) 67 | ``` 68 | 69 | 越往后,时间越长 70 | 71 | ## 优化办法 72 | 73 | - 利用主键索引来加速分页查询;(前提:主键连续) 74 | 75 | 写法一: 76 | 77 | ```sql 78 | neti> select id,name from t_test where id > 9000000 limit 100 79 | [2020-06-07 20:13:52] 100 rows retrieved starting from 1 in 60 ms (execution: 26 ms, fetching: 34 ms) 80 | ``` 81 | 82 | 可以看到值用了 60 毫秒; 83 | 84 | 写法二: 85 | 86 | ```sql 87 | neti> select id,name from t_test where id > 9000000 and id <= 9000000+100 88 | [2020-06-07 20:15:33] 100 rows retrieved starting from 1 in 42 ms (execution: 10 ms, fetching: 32 ms) 89 | ``` 90 | 91 | 这个耗时更少。 92 | 93 | - 如果主键值不连续,怎么分页? 94 | 95 | - 使用逻辑删除,不会造成主键不连续 96 | - 利用主键索引加速,再做表连接查询 97 | 98 | 下面是这个方案的写法 99 | 100 | ```sql 101 | neti> select t.id, t.name 102 | from t_test t 103 | join(select id from t_test limit 9000000,100) tmp on t.id = tmp.id 104 | [2020-06-07 20:24:02] 100 rows retrieved starting from 1 in 1 s 956 ms (execution: 1 s 935 ms, fetching: 21 ms) 105 | 106 | ``` 107 | 108 | 这个语句是想用子查询先利用 **主键索引** 过滤出 100 条数据,再关联出这 100 条的数据。不过这个语句在执行计划里面并不是我们希望的这样去查询的。 109 | 110 | 虽然是这样,但是比 limit 还是要快上几百毫秒 111 | 112 | - 其他解决办法 113 | 114 | 业务上限定不可以查询早期数据,或则不给出直接跳到多少条之后的入口 115 | 116 | ![image-20200607203427729](./assets/image-20200607203427729.png) 117 | 118 | -------------------------------------------------------------------------------- /docs/ali-new-retail/05/06.md: -------------------------------------------------------------------------------- 1 | # 读多写少和读多写多 2 | 3 | 本节没有什么动手操作,介绍一些业务场景下,如何更好的使用 MySQL 数据库。 4 | 5 | ## 读多写少 6 | 7 | 普遍来说,绝大多数的系统都是读多写少的,比如: 8 | 9 | - 电商系统: 10 | 11 | 如:购买商品,大部分的时间都是在浏览商品,只有在下订单的时候才产生写操作。 12 | 13 | - 新闻系统 14 | 15 | - 论坛系统 16 | 17 | - 在线教育系统 18 | 19 | 这种场景中,使用普通的关系型数据库就可以实现,并发大的话,还可以使用数据库集群。 20 | 21 | ## 写多读少 22 | 23 | 比如滴滴打车:下单之后,会将行程信息轨迹不断上传到服务器,进行写入,很少会查询这次行程的所有信息。 24 | 25 | ![image-20200607210627524](./assets/image-20200607210627524.png) 26 | 27 | 还比如:大学食堂系统,大量的刷卡信息被写入,这些信息却很少被查询 28 | 29 | 那么写多读少的场景使用普通关系型数据库可以吗? 30 | 31 | ## 写多读少的解决方案 32 | 33 | - 如果是低价值的数据,可以采用 NoSQL 数据库来存储这些数据 34 | 35 | 比如行程坐标,数据量大,但是每一条数据的价值不是很大,采用事务型数据库,由于事务机制,写入就很慢; 36 | 37 | ![image-20200607211404137](./assets/image-20200607211404137.png) 38 | 39 | 传统数据使用 MySQL,低价值数据使用 NoSQL 40 | 41 | - 如果是高价值的数据,可以用 TokuDB 来保存 42 | 43 | 由于 NoSQL 大部分都不支持事物,所以需要使用事务型的数据库来写入。 44 | 45 | TokuDB 的写入速度是 InnoDB 的 9~20 倍。 46 | 47 | ![image-20200607211346366](./assets/image-20200607211346366.png) 48 | 49 | 传统数据使用 MySQL,高价值写入多使用 TokuDB 来写入。 50 | 51 | ## 写多读多 52 | 53 | 这种场景并不多见,非常特殊。 54 | 55 | 比如微信、QQ都有离线留言的功能。这两个的软件用户很多,有很多离线消息需要存储,用户上线之后,需要获取离线消息。所以在数据库这里看,就是读多写多的。 56 | 57 | 传统关系型数据库是没有办法承载这种场景的。可以使用 NoSQL 来存储 58 | 59 | ## 数据库集群方案缺点 60 | 61 | 数据库集群的 **读写速度低于单节点数据库实例** 62 | 63 | ![image-20200607211831410](./assets/image-20200607211831410.png) 64 | 65 | 例如:MyCat 通过路由插入到集群上某一个节点上。因为需要做一些额外的操作,因此相比慢。 66 | 67 | 我们使用他是看中了它的优点 68 | 69 | ## 数据库集群方案优点 70 | 71 | 数据库集群能支持 **更大规模的并发访问**,并且 **存放更多的数据** 72 | 73 | -------------------------------------------------------------------------------- /docs/ali-new-retail/05/07.md: -------------------------------------------------------------------------------- 1 | # 删改数据如何避免锁表? 2 | 3 | ## 什么是锁机制? 4 | 5 | 平时 MySQL 执行语句的时候,会自动给数据加锁。 6 | 7 | InnoDB 采用的是行级锁,删改数据的时候,MySQL 会锁住记录。 8 | 9 | ![image-20200607212441588](./assets/image-20200607212441588.png) 10 | 11 | 比如:上图更新 3 条语句,只会锁住这三条记录。被锁住的记录有什么表现?这需要根据它使用的锁来说明 12 | 13 | ## 共享锁和排它锁 14 | 15 | 行级锁分为: 16 | 17 | - 共享锁(S 锁) 18 | - 排它锁(X 锁) 19 | 20 | 共享锁和排它锁,**都不允许 **其他事务 **执行写操作**,但是可以读数据。 21 | 22 | 排他锁不允许对数据再加另外的锁。 23 | 24 | ## 共享锁 25 | 26 | 只有 serializable 事务隔离级别,才会给数据添加共享锁。也可以手动添加共享锁 27 | 28 | ```sql 29 | select ... from ... lock in share mode; 30 | ``` 31 | 32 | 事务不提交,该共享锁不会被释放,其他事务只能读取数据,而不能写数据。 33 | 34 | 如下面的测试 35 | 36 | ```sql 37 | -- 会话 1 38 | -- 开启事物,并查询前 10 条记录 39 | BEGIN; 40 | SELECT 41 | * 42 | FROM 43 | t_test 44 | WHERE 45 | id <= 10 LOCK IN SHARE MODE; 46 | 47 | -- 先不提交事务,去 会话 2,执行更新操作 48 | COMMIT; 49 | 50 | 51 | -- 会话 2 52 | -- 开启事物,并执行更新语句 53 | BEGIN; 54 | UPDATE t_test 55 | SET `name` = 'abc' 56 | WHERE 57 | id <= 10; 58 | -- 会发现更新语句被阻塞了,要等待会话 1 释放共享锁 59 | 60 | -- 可以回滚该事务,不让修改生效 61 | ROLLBACK; 62 | ``` 63 | 64 | ## 排他锁 65 | 66 | MySQL 会 **默认** 给添加、修改和删除记录,设置排他锁。 67 | 68 | 手动添加排他锁的语法为 69 | 70 | ```sql 71 | select ... from ... for update; 72 | ``` 73 | 74 | 可以对该数据进行查询,但是不能对加了排它锁的数据进行修改。(同时也不能对该数据加排他锁了) 75 | 76 | ## 如何减少并发操作的锁冲突? 77 | 78 | 把复杂的 SQL 语句,拆分成多条简单的 SQL 语句。 79 | 80 | 复杂 SQL 语句执行时间长,锁时间长,拆分成简单的语句,每次锁定数据少,锁时间短 -------------------------------------------------------------------------------- /docs/ali-new-retail/05/08.md: -------------------------------------------------------------------------------- 1 | # 技术面试(初级) 2 | 3 | 从开发角度审视数据库的设计细节,就如同前面讲解的几个知识点。 4 | 5 | 要点回顾: 6 | 7 | - 为了方便把数据迁移到集群,主键该不该用 UUID 8 | 9 | - 订单号与流水号是不是一回事? 10 | 11 | 订单号必须满足唯一性,而流水号不用满足强一致性 12 | 13 | 流水号能携带比订单号更多的信息 14 | 15 | - 如果系统上线了,你这么维护表结构? 16 | 17 | 不影响业务的维护操作可以在线执行,先做好备份。 18 | 19 | 影响业务的维护操作,要使用专门的工具,如 PerconaToolkit 工具 20 | 21 | - 系统内部的业务图片怎么存储? 22 | 23 | 小型方案:使用图床服务器, nginx 或云存储 24 | 25 | 专业方案:使用 MongoDB 的 GridFS 搭建集群图床服务器 26 | 27 | - 你们系统的负载怎么样? 28 | 29 | 读多写少的方案:MySQL + NoSQL 30 | 31 | 写多读少的方案:MySQL + TokuDB 32 | 33 | - 数据表用逻辑删除还是物理删除? 34 | 35 | 使用逻辑删除,定时归档历史表 36 | 37 | - 数据记录很多的时候,如何对分页语句优化? 38 | 39 | 用主键索引加速,然后用表连接获取具体数据。 40 | 41 | - 怎么避免并发操作的时候,数据不一致的问题? 42 | 43 | 使用乐观锁机制,在数据中加上版本号字段,先获取版本号,再更新的时候使其作为条件,因为由行级锁,所以在数据库层面会保证这个版本号判定是原子的。别的事务修改成功之后,你拿到的版本号就对不上,修改失败了 -------------------------------------------------------------------------------- /docs/ali-new-retail/05/README.md: -------------------------------------------------------------------------------- 1 | # 常见问题与企业级解决方案-初级 2 | 适用于「直面」项目面试官 + 工作中技高一筹】 3 | 4 | 本章梳理新零售数据设计与实战中常见的问题,并给出企业级解决方案,当你将此作为项目经历写进简历,你也可以「直面」项目面试官。 5 | 6 | 本章的重点是:**如何高效的使用 MySQL 数据库**,比如:如何用设计出来的数据表去参加 **秒杀业务**,如何对千万的数据进行快速分页,等等比较有代表性的内容。 7 | 8 | - [主键用数字还是 UUID?](./01.md) 9 | - [在线修改表结构](./02.md) 10 | - [订单和流水号的区别](./03.md) 11 | - [逻辑删除还是物理删除](./04.md) 12 | - [千万记录,如何快速分页](./05.md) 13 | - [读多写少和读多写多](./06.md) 14 | - [删改数据如何避免锁表?](./07.md) 15 | -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607140909217.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607140909217.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607141059856.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607141059856.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607141942571.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607141942571.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607152047353.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607152047353.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607173145363.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607173145363.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607180027818.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607180027818.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607203427729.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607203427729.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607210627524.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607210627524.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607211346366.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607211346366.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607211404137.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607211404137.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607211831410.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607211831410.png -------------------------------------------------------------------------------- /docs/ali-new-retail/05/assets/image-20200607212441588.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/05/assets/image-20200607212441588.png -------------------------------------------------------------------------------- /docs/ali-new-retail/06/02.md: -------------------------------------------------------------------------------- 1 | # 什么是存储过程 2 | 3 | ## 数据库编程 4 | 5 | 写 SQL 脚本,数据库把它编译成二进制代码, 6 | 7 | ![image-20200610214229906](./assets/image-20200610214229906.png) 8 | 9 | - 存储过程:不能写在 SQL 语句中调用,**只能单独调用**。 10 | 11 | - 函数:是一个特殊的存储过程,只能查询并返回数据;**不能单独调用** 12 | 13 | 如之前的各种函数,`now()` 等 14 | 15 | - 触发器:一种特殊的存储过程;**不需要调用**,写好触发条件,会自动触发 16 | 17 | 这里只是了解,但是结论是:**放弃使用他们**; 18 | 19 | 在银行中可能会常用到:比如国外的花旗银行,他们 **不想对外暴露表结构**,从而编写了大量的存储过程(就如同我们提供接口),外部(衍生的第三方业务;或则是外包出去的功能模块?)带上对应的参数调用即可。这样就能很好的保护他们的数据表 20 | 21 | ## 存储过程的优点 22 | 23 | - 存储过程是编译过的 SQL 脚本,所以执行速度非常快 24 | 25 | - 不用去校验 SQL 语法 26 | - 不用再次编译 27 | 28 | - 实现了 SQL 编程,可以降低锁表的时间和锁表的方位 29 | 30 | 在存储过程中可以定义变量,把查询出来的结果保存,利用来计算; 31 | 32 | 比如子查询就是,查询出来的数据无法定义变量影响,变成一个相关子查询,导致锁表数据多。 33 | 34 | 先查询出来结果,再以变量的形式拼成 SQL,就不用锁表那么多了 35 | 36 | - 对外封装了表结构,提升了数据库的安全性 37 | 38 | ## 编写存储过程案例 39 | 40 | 根据部门名称,查询部门用户信息。 41 | 42 | ```sql 43 | CREATE 44 | DEFINER = CURRENT_USER PROCEDURE `p1`(IN p_dname varchar(20)) 45 | BEGIN 46 | SELECT e.id, e.ename, e.sex, e.married, j.job 47 | FROM t_emp e 48 | JOIN t_dept d ON e.dept_id = d.id 49 | join t_job j on e.job_id = j.id 50 | where d.dname = p_dname; 51 | END; 52 | 53 | -- DEFINER :定义 54 | -- CURRENT_USER:哪些用户可以使用,比如 `root`@`%` 55 | -- PROCEDURE:声明为存储过程 56 | -- 后面是过程的名称,和定义入参 57 | 58 | 59 | -- 调用存储过程 60 | call p1('零售部'); 61 | ``` 62 | 63 | 上面是一个简单的案例,这里来一个更加复杂的案例:插入实习员工数据的时候,如果是男性,就分配到网商部实习;如果是女性,就分配到零售部实习 64 | 65 | ```sql 66 | -- 在这之前,先增加一个实习的职位 67 | INSERT INTO neti.t_job (id, job) VALUES (9, '实习生'); 68 | 69 | 70 | CREATE 71 | DEFINER = CURRENT_USER PROCEDURE `p2`(in p_wid varchar(20), 72 | in p_ename varchar(20), 73 | in p_sex char(1), 74 | in p_marred boolean, 75 | in p_education tinyint, 76 | in p_tel varchar(11)) 77 | BEGIN 78 | -- 定义一个变量,保存部门编号 79 | declare dept_id int; 80 | -- 条件判断 81 | case 82 | when p_sex = '女' then 83 | set dept_id = 3; -- 然后赋值 84 | else 85 | set dept_id = 4; 86 | end case; 87 | insert into t_emp(wid, ename, sex, married, education, tel, dept_id, hiredate, job_id, `status`) 88 | values (p_wid, p_ename, p_sex, p_marred, p_education, p_tel, dept_id, curdate(), 9, 1); 89 | END; 90 | 91 | call p2('TE0023', '陈婷婷', '女', false, 1, '12345678999'); 92 | call p2('TE0024', '陈火', '男', false, 1, '12345678900'); 93 | ``` 94 | 95 | 存储过程这些在 DataGrip 中英文名称叫 routines,官方名称也是这个。汉化含义是:例程 -------------------------------------------------------------------------------- /docs/ali-new-retail/06/03.md: -------------------------------------------------------------------------------- 1 | # 什么是函数? 2 | 3 | 之前用过数据库定义好的函数,我们自己也可以自定义函数; 4 | 5 | 函数只能返回一个结果(或则不返回),不能是多条; 6 | 7 | 编写计算个个税函数,2017 的计算公式为:`个税 =(收入- 3500)x税率-扣除数` 8 | 9 | ![image-20200610223023285](./assets/image-20200610223023285.png) 10 | 11 | ```sql 12 | create 13 | -- 定义类型变成了 function 14 | -- 入参中,没有类 in 15 | -- 返回值使用 returns 声明,并声明了返回的数据类型 16 | definer = CURRENT_USER function p3(salary decimal(10, 2)) returns decimal(10, 2) 17 | READS SQL DATA -- 这两个不知道是啥意思,反正就这样写 18 | DETERMINISTIC 19 | begin 20 | declare temp decimal; 21 | declare tax decimal; -- 个税 22 | set temp = salary - 3500; 23 | 24 | case 25 | when temp <= 0 then 26 | set tax = 0; 27 | when temp > 0 and temp <= 1500 then 28 | set tax = temp * 0.03 - 0; 29 | when temp > 1500 and temp <= 4500 then 30 | set tax = temp * 0.1 - 105; 31 | when temp > 4500 and temp <= 9000 then 32 | set tax = temp * 0.2 - 555; 33 | when temp > 9000 and temp <= 35000 then 34 | set tax = temp * 0.25 - 1005; 35 | when temp > 35000 and temp <= 55000 then 36 | set tax = temp * 0.3 - 2755; 37 | when temp > 55000 and temp <= 80000 then 38 | set tax = temp * 0.35 - 5505; 39 | when temp > 80000 then 40 | set tax = temp * 0.45 - 13505; 41 | end case; 42 | return tax; 43 | end; 44 | 45 | -- 调用 46 | select p3(4000); 47 | select p3(5000); 48 | select p3(20000); 49 | select p3(1000000); 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /docs/ali-new-retail/06/04.md: -------------------------------------------------------------------------------- 1 | # 什么是触发器 2 | 3 | 一种特殊的存储过程;**不需要调用**,写好触发条件,会自动触发 4 | 5 | 编写触发器:修改部门编号,同步更新该部门员工的 dept_id 字段。 6 | 7 | ![image-20200610230140947](./assets/image-20200610230140947.png) 8 | 9 | 上图在部门表 t_dept 上定义了一个触发器,在部门数据更新之后(AFTER),去执行下面的 update 语句,里面有两个固定的变量:new.id 其中的 new 是当前部门表被更新的这一行数据,old,则是部门表更新之前的数据。 10 | 11 | 作用就是:当部门这条数据的 ID 变更了,那么久同步变更关联这条数据的 ID 为新的数据。 -------------------------------------------------------------------------------- /docs/ali-new-retail/06/05.md: -------------------------------------------------------------------------------- 1 | # 为什么不要使用存储过程? 2 | 3 | 为什么放弃存储过程、触发器、函数? 4 | 5 | 在数据库集群场景里,因为存储过程、触发器、函数都是在本地数据库执行,所以无法兼容集群场景; 6 | 7 | 什么时候使用数据库集群? 8 | 9 | 并发在 200 左右,使用单节点 MySQL,访问量达到并发 2000,则需要集群了。 -------------------------------------------------------------------------------- /docs/ali-new-retail/06/06.md: -------------------------------------------------------------------------------- 1 | # 如何避免偷换交易中的商品信息? 2 | 3 | 说不清的购物纠纷,简单说就是,客户购买商品后,商家就把商品信息改掉了,这样就说不清你买的是什么了。 4 | 5 | 比如:你在宝贝详情里面看到是 **进口奶粉**,你拍下后,卖家发货给你,然后就把 **进口** 从详情里面删掉了。发给你的货也是国内的。这就出现了购物纠纷。 6 | 7 | 如何避免篡改商品信息? 8 | 9 | B2B 电商平台,通常采用保存历次商品修改信息、降低搜索排名等方案来约束。 10 | 11 | 对于 B2C 电商平台,因为是自己经营的,值需要保存历次商品修改信息即可。 12 | 13 | ## 如何保存商品历次修改信息? 14 | 15 | ![image-20200611223654450](./assets/image-20200611223654450.png) 16 | 17 | - 每次修改,都先备份该数据,然后再修改 18 | - 当用户在订单详情中,查看自己购买商品的时候,就需要查询 sku_old 表数据渲染。(类似快照?) 19 | - 当 old 表历史数据太多的时候,就可以考虑迁移到归档库中 20 | 21 | 对于我们之前表的修改: 22 | 23 | - 新增 spu_old 和 sku_old 表 24 | 25 | 表结构和他们原来的表一致,不同的是:新增一个 old_id 来保存原来表的主键 ID;因为 old 表需要保存多次商品修改记录 26 | 27 | - 订单表 t_order 表中。 28 | 29 | 新增一个 old_id 字段,用来关联当前版本的商品信息(快照); -------------------------------------------------------------------------------- /docs/ali-new-retail/06/07.md: -------------------------------------------------------------------------------- 1 | # 如何抵御 XSS 攻击 2 | 3 | ## 什么是 XSS 攻击? 4 | 5 | XSS 是跨站脚本攻击,让浏览器渲染 DOM 的时候意外的执行了恶意 JS 代码。 6 | 7 | XSS 攻击的原理是:在网页中嵌入一个恶意脚本。 8 | 9 | ```html 10 | 59 | ``` 60 | 61 | 对于 antisamy.xml 是 antisamy 的一个策略配置文件,自带的 jar 包中,已经包含了好几个规则,有宽松的,有严格的(可以吧 img 标签都删除)。 62 | 63 | ## 本章要点回顾 64 | 65 | - 电商系统,秒杀的时候如何避免商品超售? 66 | 67 | 数据库使用乐观锁,使用 Redis 的事务机制。 68 | 69 | - 为什么不用存储过程? 70 | 71 | 不适合集群场景。 72 | 73 | - 如何预防电商交易中,卖家偷换商品信息? 74 | 75 | 商品信息修改要备份。相当于做快照 76 | 77 | -------------------------------------------------------------------------------- /docs/ali-new-retail/06/README.md: -------------------------------------------------------------------------------- 1 | # 常见问题与企业级解决方案-进阶 2 | 3 | 【进阶】常见问题与企业级解决方案【适用于与“项目面试官”正面硬钢+价值提升必备】 4 | 5 | 本章梳理业务中较难和较复杂的问题,并通过案例与代码等方式给出企业级解决方案,为你的独当一面的能力保驾护航,偷偷告诉你,掌握本章几个高阶问题,让你项目面试可以与面试官:正面硬钢哦。 6 | 7 | - [如何实现商品秒杀](./01.md) 8 | - [什么是存储过程?](./02.md) 9 | - [什么是函数?](./03.md) 10 | - [什么是触发器?](./04.md) 11 | - [为什么不要使用存储过程?](./05.md) 12 | - [如何避免偷换交易中的商品信息?](./06.md) 13 | - [如何抵御 XSS 攻击?](./07.md) -------------------------------------------------------------------------------- /docs/ali-new-retail/06/assets/image-20200609214755323.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/06/assets/image-20200609214755323.png -------------------------------------------------------------------------------- /docs/ali-new-retail/06/assets/image-20200609220247456.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/06/assets/image-20200609220247456.png -------------------------------------------------------------------------------- /docs/ali-new-retail/06/assets/image-20200609221113157.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/06/assets/image-20200609221113157.png -------------------------------------------------------------------------------- /docs/ali-new-retail/06/assets/image-20200610214229906.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/06/assets/image-20200610214229906.png -------------------------------------------------------------------------------- /docs/ali-new-retail/06/assets/image-20200610223023285.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/06/assets/image-20200610223023285.png -------------------------------------------------------------------------------- /docs/ali-new-retail/06/assets/image-20200610230140947.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/06/assets/image-20200610230140947.png -------------------------------------------------------------------------------- /docs/ali-new-retail/06/assets/image-20200611223654450.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/06/assets/image-20200611223654450.png -------------------------------------------------------------------------------- /docs/ali-new-retail/06/assets/image-20200611224913567.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/06/assets/image-20200611224913567.png -------------------------------------------------------------------------------- /docs/ali-new-retail/07/01.md: -------------------------------------------------------------------------------- 1 | # 数据库/程序 缓存如何选? 2 | 3 | ## 为什么要缓存数据? 4 | 5 | 数据库中的数据是存放在硬盘上的,从数据库中读取肯定比内存慢。 6 | 7 | 放内存中,一般会给数据一个过期时间,不常用的就会自动清理掉。 8 | 9 | ## 数据库性能 10 | 11 | 经过优化的 MySQL 每秒可以处理 5000 次读取,或则 3000 次写入,负载不高的时候,响应时间通常在 10ms 以内,但是在 1 万并发的时候,要保证 10ms 以内的响应速度,任何数据库都做不到。 12 | 13 | 这个时候就可以用内存来缓存数据了。但是问题来了,这个数据是由谁来缓存? 14 | 15 | ![image-20200613215435043](./assets/image-20200613215435043.png) 16 | 17 | 由程序还是数据库? 18 | 19 | ## 数据库缓存 20 | 21 | 程序和数据库都有自己独立的一套缓存方案。 22 | 23 | MySQL 缓存是 KV 结构的,Key 是执行过的 SQL 语句,Value 是查询的结果。如果执行添加、修改、删除,或则修改表结构,都会造成缓存清空。 24 | 25 | ## 数据查询过程 26 | 27 | 执行 SQL 语句,MySQL 先查询缓存。命中数据,就从缓存中提取数据;没有命中,就从数据库中查询数据,同时会缓存到内存中。 28 | 29 | ![image-20200613215906767](./assets/image-20200613215906767.png) 30 | 31 | ## 数据库缓存注意事项 32 | 33 | 默认是关闭的,要使用需要先开启。但是 MySQL 8+ 后,去掉了查询缓存这个功能。 34 | 35 | - 所有对数据加锁的事务中,不会使用查询缓存 36 | - 比如:一个事务中,update 后,使用 select 就不会使用缓存 37 | - 查询语句必须一模一样,才有机会命中缓存 38 | 39 | ## 该不该使用数据库缓存? 40 | 41 | MySQL8+ 去掉了查询缓存,Oracle 官方也不推荐使用查询缓存。 42 | 43 | 查询下 MySQL8.0 的查询缓存是否支持: 44 | 45 | ```sql 46 | show variables like '%query_cache'; 47 | -- 查询结果是 48 | have_query_cache,NO 49 | ``` 50 | 51 | 下图是 mysql 5.7 的查询结果 52 | 53 | ![image-20200613220518698](./assets/image-20200613220518698.png) 54 | 55 | 可以看到是支持,但是查询缓存没有开启。 56 | 57 | **数据库缓存的根本问题是**:不能细粒度设置哪些表需要缓存,当 MySQL 缓存了很多结果的时候,一条更新语句就会让缓存全部作废,这严重的加重了内存管理的负担。 58 | 59 | 哪些数据适合缓存?很少修改的数据,并且经常使用的数据,才值得去缓存,在 MySQL 中,我们无法细粒度的来选择。 60 | 61 | ## 程序缓存的优势 62 | 63 | Redis、Memcached 这些缓存产品,都可以在程序中细粒度的设置哪些查询需要缓存,哪些不需要。 64 | 65 | 对于 java 来说,spring 框架提供了缓存技术的支持。 66 | 67 | ## SpringCache 技术 68 | 69 | ```java 70 | @Cacheable("Cache1") 71 | public User get(Long id){ 72 | // 执行查询 73 | // 返回的结果会被缓存 74 | return User对象; 75 | } 76 | ``` 77 | 78 | 建议:单表查询结果可以缓存,表连接查询不建议缓存。因为你不太确定哪张表是经常修改的。 79 | 80 | ```java 81 | // 让缓存失效的注解 82 | @CacheEvict(value="Cache1") 83 | public void delete(Long id){ 84 | // 执行删除操作 85 | } 86 | ``` 87 | 88 | -------------------------------------------------------------------------------- /docs/ali-new-retail/07/04.md: -------------------------------------------------------------------------------- 1 | # 本章总结 2 | 3 | - 如何抵御 XSS 攻击? 4 | 5 | 对数据过滤或则转义,再保存到数据库 6 | 7 | - 智能才拆分订单,让最近的仓库发货 8 | 9 | - 用中文分词提取关键字信息,搜索商品 -------------------------------------------------------------------------------- /docs/ali-new-retail/07/README.md: -------------------------------------------------------------------------------- 1 | # 常见问题与企业级解决方案-高阶 2 | 【高阶】常见问题与企业级解决方案【高薪 Offer 的神助攻 + 工作晋升必备】 3 | 4 | 本章问题持续升级,作为企业级核心痛点问题,讲师在此同样也给出企业级的解决方案, 5 | 掌握此部分问题的解决方案,高薪 Offer,有如神助。 6 | 7 | - [数据库/程序 缓存如何选?](./01.md) 8 | - [智能拆分订单](./02.md) 9 | - [中文分词技术](./03.md) 10 | - [本章总结](./04.md) -------------------------------------------------------------------------------- /docs/ali-new-retail/07/assets/image-20200613215435043.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/07/assets/image-20200613215435043.png -------------------------------------------------------------------------------- /docs/ali-new-retail/07/assets/image-20200613215906767.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/07/assets/image-20200613215906767.png -------------------------------------------------------------------------------- /docs/ali-new-retail/07/assets/image-20200613220518698.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/07/assets/image-20200613220518698.png -------------------------------------------------------------------------------- /docs/ali-new-retail/07/assets/image-20200613225041583.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/07/assets/image-20200613225041583.png -------------------------------------------------------------------------------- /docs/ali-new-retail/07/assets/image-20200613231042478.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/07/assets/image-20200613231042478.png -------------------------------------------------------------------------------- /docs/ali-new-retail/07/assets/image-20200614085126417.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/07/assets/image-20200614085126417.png -------------------------------------------------------------------------------- /docs/ali-new-retail/07/assets/image-20200614091852158.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/07/assets/image-20200614091852158.png -------------------------------------------------------------------------------- /docs/ali-new-retail/07/assets/image-20200614111515949.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/07/assets/image-20200614111515949.png -------------------------------------------------------------------------------- /docs/ali-new-retail/08/02.md: -------------------------------------------------------------------------------- 1 | # SQL 语句的优化 2 | 3 | 主要围绕如何使用索引展开 4 | 5 | - 不要把 select 子句写成 `select *` 6 | 7 | 1. 返回结果集数量太多了 8 | 2. 需要先读取表结构,换成字段名称 9 | 10 | - 谨慎使用模糊查询 11 | 12 | ```sql 13 | select ename from t_emp where ename like '%S%' 14 | ``` 15 | 16 | 「%」在左边,无法使用左前缀索引查询。 17 | 18 | - 对 order by 排序的字段设置索引 19 | 20 | 索引是二叉树机制,索引建立就是有序的了,所以不用做额外的排序计算 21 | 22 | - 少用 is null 和 is not null 23 | 24 | 会让 mysql 跳过索引,进行全表查询。 25 | 26 | null 值无法进行排序,所以不会记录在二叉树里,所以与 null 值有关的判定都不会走索引。 27 | 28 | ```sql 29 | -- 查询奖金不为空的数据 30 | select ename from t_emp where comm is not null; 31 | -- 可以改写成 32 | select ename from t_emp where comm >= 0 33 | -- 还可以对 comm 设置非空约束,使用 -1 表示没有奖金。 34 | ``` 35 | 36 | - 尽量少用 `!=` 运算符 37 | 38 | 无法利用二叉树机制。就无法走索引了。 39 | 40 | ```sql 41 | selecet ename from t_emp where deptno != 20; 42 | -- 可以改写成 43 | selecet ename from t_emp where deptno > 20 and deptno < 20; 44 | ``` 45 | 46 | - 尽量少用 OR 运算索引 47 | 48 | 同样会让索引失效, OR 之前的会走索引,之后的就无法走索引了 49 | 50 | ```sql 51 | -- =20 走索引,=30 无法走索引 52 | select ename from t_emp where deptno = 20 or deptno=30; 53 | 54 | -- 可以改写为两个 sql 55 | select ename from t_emp where deptno = 20 56 | union all 57 | select ename from t_emp where deptno = 30; 58 | ``` 59 | 60 | - 尽量少用 in 和 not int 运算符 61 | 62 | 在某些情况下使用 in 能走索引,[参考 mysql 高性能一书](/mysql-tutorial/high-performance/05/04.md#支持多种过滤条件) 63 | 64 | 也可以将 in 改写成 union 关联多个拆分开的查询 65 | 66 | - 避免条件语句中的数据类型转换 67 | 68 | ```sql 69 | select ename from t_emp where deptno='20' 70 | ``` 71 | 72 | 在我们的苦衷 deptno 是整数类型,这里写了字符串类型,mysql 需要先转换类型,再匹配,这会影响执行速度 73 | 74 | - 在表达式左侧使用 **运算符和函数** 都会让索引失效 75 | 76 | ```sql 77 | -- 查询年薪超过 12 万的员工 78 | select ename from t_emp where salary * 12 > 100000; 79 | -- 可以改写为 80 | select ename from t_emp where salary > 100000 / 12; 81 | 82 | -- 查询 2000 年以后入职的员工 83 | select ename from t_emp where year(hiredate) >= 2000; 84 | -- 可以改写为 85 | select ename from t_emp where year >= '2000-01-01 00:00:00'; 86 | ``` 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /docs/ali-new-retail/08/03.md: -------------------------------------------------------------------------------- 1 | # MySQL 参数优化 2 | 3 | ## 优化最大连接数 4 | 5 | `max_connections` 是 MySQL 最大并发连接数,默认值是 151,最大值允许为 16384; 6 | 7 | 实际连接数设置为:最大连接数的 85% 较为合适 8 | 9 | ```sql 10 | -- 目前设置的最大并发连接数量 11 | show variables like 'max_connections' 12 | -- 目前实际连接数量 13 | show status like 'max_used_connections'; 14 | ``` 15 | 16 | `/etc/my.cnf` 中增加 `max_connections=5000` ,该配置需要重启数据库 17 | 18 | MySQL 为每个链接 **创建缓冲区**,所以不应该盲目上调最大连接数。需要考虑你的服务器硬件,如内存是否能支持到这么大的连接数量。 19 | 20 | ```sql 21 | -- 比如,在满负荷 3000 并发下,消耗内存为 800M 内存 22 | max_connections=3000 23 | -- 那么你就要计算你设置的并发连接数量消耗内存是否内存能装得下 24 | ``` 25 | 26 | ## 优化请求堆栈 27 | 28 | `back_log` 是存放执行请求的堆栈大小,默认值是 50;这个可以理解为队列,当并发连接达到了最大值,剩下的则会放入这个请求堆栈中; 29 | 30 | ## 修改并发线程数 31 | 32 | `innodb_thread_concurrency` 是并发线程数量,默认是 0,无限制; 33 | 34 | 这个是多线程的相关的知识了,在CPU 密集型的场景下,设置为何 CPU 核数一样的较佳。 35 | 36 | 视频中推荐:设置为 CPU 核心数的两倍 37 | 38 | ## 修改链接超时 39 | 40 | `wait-timeout` 超时时间,单位是秒;默认超时时间为 8 小时。 41 | 42 | 链接长期不用,又不销毁,很是浪费资源 43 | 44 | ## InnoDB 的缓存 45 | 46 | 这里说的不是 **查询缓存**,另外查询缓前面说过了,MySQL 8+ 已经去掉了这个功能。 47 | 48 | ![image-20200614182205307](./assets/image-20200614182205307.png) 49 | 50 | 缓存里面保存了两类数据:部分数据和部分索引 51 | 52 | ## 修改 InnoDB 缓存大小 53 | 54 | `innodb_buffer_pool_size` 是 InnoDB 的缓存容量,默认是 128M。 55 | 56 | 可以设置为主机内存的 `70%~80%` 57 | 58 | 59 | 60 | ## 小结 61 | 62 | 数据库参数优化配置有很多,这里只是列出了,可以明显改善数据库性能的参数。 -------------------------------------------------------------------------------- /docs/ali-new-retail/08/04.md: -------------------------------------------------------------------------------- 1 | # MySQL 慢查询日志 2 | 3 | ## 慢查询日志作用 4 | 5 | - 慢查询日志会把查询耗时,超过规定时间的 SQL 语句记录下来 6 | - 利用慢查询日志,定位分析性能的瓶颈 7 | 8 | 默认情况下,MySQL 是不启用慢查询日志的。 9 | 10 | ```sql 11 | show variables like 'slow_query%'; 12 | ``` 13 | 14 | | Variable\_name | Value | 15 | | :--- | :--- | 16 | | slow\_query\_log | OFF | 17 | | slow\_query\_log\_file | /usr/local/mysql/sql\_log/slowlog.log | 18 | 19 | `slow_query_log`:慢查询开启状态 20 | 21 | `slow_query_log_file`:慢查询日志存放位置 22 | 23 | ## 开启慢查询日志 24 | 25 | ```bash 26 | # 开启慢查询日志 27 | slow_query_log=ON 28 | # 查询超时时间,单位 秒 29 | long_query_time=1 30 | ``` 31 | 32 | 还可以[参考笔者的另一文章学习慢查询的知识](/mysql-tutorial/imooc-mysql8/07/#配置慢查询日志) 33 | 34 | 除了配置文件,还可以使当次 mysql 运行期间生效的配置方式,运行以下语句 35 | 36 | ```sql 37 | set global slow_query_log=on; 38 | ``` 39 | 40 | 使用语句来运行超过 1 秒钟,来查看慢查询日志信息 41 | 42 | ```sql 43 | select sleep(2); -- 休眠 2 秒钟 44 | ``` 45 | 慢查询日志文件 `/usr/local/mysql/sql\_log/slowlog.log` 46 | ``` 47 | # Time: 2020-06-12T03:44:19.415383Z 48 | # User@Host: root[root] @ gateway [192.168.56.1] Id: 8 49 | # Query_time: 2.000411 Lock_time: 0.000000 Rows_sent: 1 Rows_examined: 0 50 | use neti; 51 | SET timestamp=1591933457; 52 | /* ApplicationName=DataGrip 2020.1.4 */ select sleep(2); 53 | ``` 54 | 55 | ## EXPLAIN 56 | 57 | 从慢查询日志看到那些 SQL 语句查询慢,那么可以通过 explain 针对这些语句进行执行计划的查看,然后分析它为什么这么慢 58 | 59 | ```sql 60 | explain 61 | select id, dname 62 | from t_dept; 63 | ``` 64 | 65 | 执行计划为 66 | 67 | | id | select\_type | table | partitions | type | possible\_keys | key | key\_len | ref | rows | filtered | Extra | 68 | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | 69 | | 1 | SIMPLE | t\_dept | NULL | index | NULL | unq\_dname | 802 | NULL | 7 | 100 | Using index | 70 | 71 | 这里 type=index 说明使用了索引,并使用了索引 kye=unq\_dname,返回了 rows=7 行数据; 72 | 73 | 如果这里 type=all,那么就是全表扫描,可以考虑优化它,让它走索引 74 | 75 | ```sql 76 | explain 77 | select id, dname 78 | from t_dept 79 | where id = 10; 80 | ``` 81 | 82 | 执行计划为 83 | 84 | | id | select\_type | table | partitions | type | possible\_keys | key | key\_len | ref | rows | filtered | Extra | 85 | | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | 86 | | 1 | SIMPLE | t\_dept | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100 | NULL | 87 | 88 | 这一条,根据主键 ID 查询的 -------------------------------------------------------------------------------- /docs/ali-new-retail/08/05.md: -------------------------------------------------------------------------------- 1 | # 本章总结 2 | 3 | 要点知识回顾 4 | 5 | - MySQL 的压力测试,普通重要 6 | - SQL 语句的优化,重要 7 | - MySQL 参数的优化,重要 8 | - MySQL 慢查询日志,重要 -------------------------------------------------------------------------------- /docs/ali-new-retail/08/README.md: -------------------------------------------------------------------------------- 1 | # 新零售系统数据库性能调优 2 | 3 | 本章内容侧重于提升同学们 SQL 语句优化的技巧,作为程序开发人员,编写出什么样的 SQL 语句才能高效快速的查询出数据呢? 4 | 索引机制为什么能加速查询?如果出现了慢查询 SQL 语句,应该如何调试? 5 | 6 | - [MySQL 压力测试](./01.md) 7 | - [SQL 语句的优化](./02.md) 8 | - [MySQL 参数优化](./03.md) 9 | - [MySQL 慢查询日志](./04.md) 10 | - [本章总结](./05.md) -------------------------------------------------------------------------------- /docs/ali-new-retail/08/assets/image-20200614150143627.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/08/assets/image-20200614150143627.png -------------------------------------------------------------------------------- /docs/ali-new-retail/08/assets/image-20200614182205307.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/08/assets/image-20200614182205307.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/01.md: -------------------------------------------------------------------------------- 1 | # 数据库集群能解决什么问题? 2 | 3 | ## 单节点和集群哪个读写更快? 4 | 5 | - 低并发情况下,单节点 MySQL 读写速度快 6 | 7 | - 高并发情况下,MySQL 集群的读写速度更快 8 | 9 | 大量并发如果集中在一个 MySQL 节点上,先不说内存撑不撑得住,磁盘 IO 都撑不住。 10 | 11 | 数据库集群的思路: 12 | 13 | - 读写分离方案 14 | - 数据切分方案 15 | 16 | ![image-20200614211428024](./assets/image-20200614211428024.png) 17 | 18 | ## 单节点数据库的弊病 19 | 20 | 大型互联网程序用户群庞大,所以架构必须要特殊设计,比如: 21 | 22 | - 微信注册用户超 10 亿 23 | - 新浪微博用户超 3.3 亿 24 | - 今日头条用户超 2.4 亿 25 | 26 | 单节点的数据库无法满足性能上的要求:单节点链接数量最大 16000 多,大量用户情况下,根本就应付不过来 27 | 28 | 单节点的数据库没有冗余设计,无法满足高可用:一个节点挂了,这个业务也就瘫痪了。 29 | 30 | 高并发下的数据库压力:2016 年除夕,微信共收发红包 **142 亿** 个,比上一年增长 75.7%,最高峰值每秒收发红包 **76 万** 个,支付峰值 **20.8 万** 次每秒,创下世界纪录。 31 | 32 | ## 常见 MySQL 集群方案 33 | 34 | 常见的 MySQL集群方案有: 35 | 36 | - PXC :同步传输 37 | 38 | 适合保存少量高价值数据 39 | 40 | - Replication:异步传输 41 | 42 | 适合保存大量数据 43 | 44 | ## PXC 与 Replication 方案对比 45 | 46 | ![image-20200614212702883](./assets/image-20200614212702883.png) 47 | 48 | - PXC 方案:事务是同步的 49 | 50 | 执行一个事务,只有当数据同步到 slave 成功后,事务才能提交成功。 51 | 52 | - Replication:事务是异步的 53 | 54 | 在 master 上提交成功了,但是异步同步失败了,在 slave 中就无法查询到数据 55 | 56 | 他们不是竞争关系,而是互补关系 -------------------------------------------------------------------------------- /docs/ali-new-retail/09/06.md: -------------------------------------------------------------------------------- 1 | # 本章总结 2 | 3 | 要点回顾 4 | 5 | 1. 探讨了为什么要使用数据库集群;普通重要 6 | 7 | 主要看项目规模的大小 8 | 9 | 2. 掌握了 Docker 虚拟机的使用;普通 10 | 11 | 3. 创建了分布式 Docker 环境;重要 12 | 13 | 4. 搭建了 PXC 数据库集群;重要 14 | 15 | 5. 搭建了 Replication 数据库集群;重要 -------------------------------------------------------------------------------- /docs/ali-new-retail/09/README.md: -------------------------------------------------------------------------------- 1 | # 新零售平台的数据库集群 2 | 新零售平台的数据库集群 【入职BAT“必杀技”】 3 | 4 | 单节点数据库不具备三高特点(高并发、高冗余、高性能),所以就需要引入数据库集群方案来应对。 5 | 本章的内容是带领,同学们搭建两种不同风格的 MySQL 集群。PXC 集群 + Replication 集群,并利用 MyCat 中间件来管理这两种集群。 6 | 7 | - [数据库集群能解决什么问题?](./01.md) 8 | - [如何使用 Docker 虚拟机](./02.md) 9 | - [分布式 Docker 环境](./03.md) 10 | - [搭建 PXC 集群](./04.md) 11 | - [搭建 Replication 集群](./05.md) 12 | - [本章总结](./06.md) -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200614211428024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200614211428024.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200614212702883.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200614212702883.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200614213149887.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200614213149887.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200614213202049.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200614213202049.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200614213454879.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200614213454879.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200614213614537.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200614213614537.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200614214714808.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200614214714808.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200614214903784.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200614214903784.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200614223408493.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200614223408493.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200615213206621.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200615213206621.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200615213442608.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200615213442608.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200615213515494.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200615213515494.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200615215035696.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200615215035696.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200615215050956.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200615215050956.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200616225005505.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200616225005505.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200616233723811.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200616233723811.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200616234217657.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200616234217657.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200616234721341.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200616234721341.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200617214708928.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200617214708928.png -------------------------------------------------------------------------------- /docs/ali-new-retail/09/assets/image-20200617214826011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/09/assets/image-20200617214826011.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/01.md: -------------------------------------------------------------------------------- 1 | # 垂直切分与水平切分 2 | 3 | ## 什么是切分? 4 | 5 | 出于 **降低数据库负载** 和 **缩表** 的目的,通常要对单节点的 MySQL 数据库做切分。 6 | 7 | 对数据库切分的方案: 8 | 9 | - 垂直切分:降低数据库负载 10 | - 水平切分:缩表 11 | 12 | ## 垂直切分 13 | 14 | 垂直切分是 **按照业务** 对数据表分类,然后把一个数据库拆分成多个独立的数据库。 15 | 16 | ![image-20200618212254757](./assets/image-20200618212254757.png) 17 | 18 | 从上到下,将一个数据库拆分成多个数据库。也就是拆分成多个小系统。 19 | 20 | ### 垂直切分的作用 21 | 22 | 垂直切分可以把数据库的 **并发压力**,**分散** 到不同的数据库节点。 23 | 24 | ![image-20200618212452578](./assets/image-20200618212452578.png) 25 | 26 | 垂直切分并不能减少单表数据量。 27 | 28 | ### 垂直切分的缺点 29 | 30 | - **不能跨 MySQL 节点做表连接查询**,只能通过接口方式解决。 31 | 32 | - 跨 MySQL 节点的事务,需要用 **分布式事物机制** 来实现 33 | 34 | ![image-20200618212715914](./assets/image-20200618212715914.png) 35 | 36 | ## 水平切分 37 | 38 | 水平切分是 **按照某个字段的某种规则**,把数据切分到多张数据表 39 | 40 | ![image-20200618212937247](./assets/image-20200618212937247.png) 41 | 42 | MySQL 有一种自带的分区技术,将一张表进行分区,按照一定的规则切分到 Linux 不同的目录下,我们给主机挂载多块硬盘,利用分区技术,就把一张表的数据存储在多块硬盘上了。 43 | 44 | 所以:水平切分的表,不一定必须在不同的数据库节点上。 45 | 46 | ### 水平切分的缺点 47 | 48 | - 不同数据表的切分规则并不一致,要根据实际业务来确定 49 | 50 | 所以需要选择切分规则丰富的中间件。推荐 MyCat 51 | 52 | - 集群扩容麻烦,需要迁移大量的数据 53 | 54 | ![image-20200618213540418](./assets/image-20200618213540418.png)随着业务的增长,分片可能会有不够用的时候,但是增加一个分片,要迁移部分数据到新的分片,路由规则计算结果就变化了,所以需要把之前存在的数据都重新路由一下到新的分片中去。 55 | 56 | 这对在线业务影响是巨大的,所以不到万不得已,不要增加分片 57 | 58 | ### 冷热数据分离 59 | 60 | 添加新的分片,**硬件成本和时间成本很大**,所以要慎重。 61 | 62 | 可以 **对分片数据做冷热数据分离**,把冷数据移除分片来缩表。 63 | 64 | ![image-20200618214243848](./assets/image-20200618214243848.png) 65 | 66 | ## 使用垂直还是水平切分? 67 | 68 | 讨论:修改数据库架构,先做垂直切分还是水平切分 69 | 70 | 情况不同,答案不同。 71 | 72 | 从小系统开始,用户越来越多时,先做水平切分,因为这个时候只是将数据库层面做了改动。 73 | 74 | 笔者大大疑问:水平拆分问题那么多,你确定只是在数据库层面改动了?但是相对来说,这种情况下,成本是最小的。 75 | 76 | ![image-20200618214534441](./assets/image-20200618214534441.png) 77 | 78 | 水平切分 + 冷热数据分离,再多的数据都能存得下。(笔者现在深有感触,存下了,用怎么办?还没有理解到核心思想) 79 | 80 | 当日活跃用户达到 50 万时,单体架构就支持不下来了。这个时候就需要将单体应用 **拆分为多个独立的子系统** 81 | 82 | ![image-20200618215047621](./assets/image-20200618215047621.png) 83 | 84 | 垂直拆分成多个独立的子系统后,子系统间的交互等方面有很多工作需要做。 85 | 86 | 所以一定要遵循:从单体项目做起,不断迭代,达到一定日活的时候,再来做垂直切分。 87 | 88 | 但是从一开始你的目标就很明确,至少要扛起日活几十万用户的需求,那么就可以从一开始就垂直切分设计成多个子系统。 -------------------------------------------------------------------------------- /docs/ali-new-retail/10/02.md: -------------------------------------------------------------------------------- 1 | # 安装 MyCat 2 | 3 | 没有官方的 MyCat 镜像,第三方也没有比较出名的,所以我们自己在 Java 容器里面安装 4 | 5 | 没有数据库中间件的年代:通常把数据切分规则记录在数据表,然后通过查询数据表得知,查询的数据保存在什么 MySQL 节点。 6 | 7 | 比如什么类型的商品被切分存储在哪一个节点上。在查询的时候,需要先查询规则表,根据规则再去某一个节点上查找结果。 8 | 9 | ![image-20200618220204807](./assets/image-20200618220204807.png) 10 | 11 | 有了数据库中间件之后:中间件保存了水平切分的规则,直接可以切分和整合数据 12 | 13 | ![image-20200618220337563](./assets/image-20200618220337563.png) 14 | 15 | 当一个查询不带路由规则时,这个查询只能被路由到所有节点查询,然后把结果在中间件中汇聚起来返回,因为中间件不知道去哪台节点上找数据。 16 | 17 | ## 为什么选 MyCat? 18 | 19 | MyCat 是给予 Java 语言的开源数据库中间件产品,相对于其他中间件产品,MyCat 的切分规则最多,功能最全。 20 | 21 | 数据库中间件产品并不会频繁更新升级,包括数据库的相关的产品也是一样,稳定胜于一切 22 | 23 | ## 下载 MyCat 24 | 25 | [MyCat 官网](http://www.mycat.org.cn/) 26 | 27 | 1.6.6 已经撤版了,那么我们就选择 [1.6.7](http://dl.mycat.org.cn/1.6.7.1/) 是最接近 1.6.6 的,这里我们下载 [Mycat-server-1.6.7.1-release-20200209222254-linux.tar](http://dl.mycat.org.cn/1.6.7.1/Mycat-server-1.6.7.1-release-20200209222254-linux.tar.gz) 28 | 29 | ## 安装 OpenJDK 镜像 30 | 31 | 前面我们学习时下载的是最小的 OpenJDK 14 的,MyCat 是基于 JDK 1.8 ,所以需要安装 OpenJDK 1.8 32 | 33 | ```bash 34 | docker pull adoptopenjdk/openjdk8 35 | docker tag adoptopenjdk/openjdk8 openjdk8 36 | docker rmi adoptopenjdk/openjdk8 37 | ``` 38 | 39 | 该镜像不是官方版的。 40 | 41 | ## 创建 Java 容器 42 | 43 | 创建 Java 容器,在数据卷放入 MyCat 44 | 45 | ```bash 46 | # 这里不加 -it 容器不久就会被退出 47 | docker run -d -it --name mycat1 48 | -v mycat1:/root/server --privileged 49 | --net=host # 这里使用的网络是宿主机的网络,不要写 swarm 网络,有可能会链接不上 mysql 节点 50 | openjdk8 51 | ``` 52 | 53 | 安装该容器 54 | 55 | ``` 56 | [root@study ~]# docker run -d -it --name mycat1 -v mycat1:/root/server --privileged --net=host openjdk8 57 | 5e16e59c7b29465eccdd570f92d84f61886bc03b14f1536d838064997715854a 58 | ``` 59 | 60 | MyCat 使用的端口有: 61 | 62 | - 8066 :数据处理,执行的 SQL 等操作 63 | - 9066:获取 MyCat 状态信息 64 | 65 | 防火墙先放行 66 | 67 | ```bash 68 | firewall-cmd --zone=public --add-port=8066/tcp --permanent 69 | firewall-cmd --zone=public --add-port=9066/tcp --permanent 70 | firewall-cmd --reload 71 | systemctl restart docker 72 | ``` 73 | 74 | 重启之后,需要注意的是,前面讲到过的 PCX 集群的启动,可以去参考前面的笔记,启动后之后再继续 75 | 76 | 进入数据卷,把 MyCat 放入数据卷中 77 | 78 | ```bash 79 | [root@study _data]# docker volume inspect mycat1 80 | [ 81 | { 82 | "Driver": "local", 83 | "Labels": null, 84 | "Mountpoint": "/var/lib/docker/volumes/mycat1/_data", 85 | "Name": "mycat1", 86 | "Options": {}, 87 | "Scope": "local" 88 | } 89 | ] 90 | [root@study _data]# cd /var/lib/docker/volumes/mycat1/_data 91 | # 这里上传看你用的是什么工具了,笔者这里用 rz 命令上传 92 | 93 | [root@study _data]# tar -xvf Mycat.tar.gz 94 | [root@study _data]# ls 95 | mycat Mycat.tar.gz 96 | 97 | # 进入容器,查看是否能看到 mycat 解压目录了 98 | [root@study _data]# docker exec -it mycat1 bash 99 | root@study:/# cd /root/server/ 100 | root@study:~/server# ls 101 | mycat Mycat.tar.gz 102 | ``` 103 | 104 | -------------------------------------------------------------------------------- /docs/ali-new-retail/10/05.md: -------------------------------------------------------------------------------- 1 | # Mycat 垂直/水平切分/全局表 2 | 3 | 垂直切分和水平切分,前面练习的时候已经实现了 4 | 5 | ## 垂直切分 6 | 7 | 就是把数据表 **切分成独立的逻辑库** 8 | 9 | ![image-20200620221957256](./assets/image-20200620221957256.png) 10 | 11 | 将不同的集群划分为一个逻辑库,然后交给 mycat 来管理。 12 | 13 | ## 水平切分 14 | 15 | MyCat 具有很多 **水平切分算法**,用户可以随意定制切分规则。 16 | 17 | 比如前面的 student 表的取模将数据路由到某一个分片上去。 18 | 19 | 下面列出一些水平切分的算法。先混个脸熟 20 | 21 | | 分片算法 | 使用场景 | 案例 | 22 | | :--------: | -------------------------- | --------------- | 23 | | 主键球模 | 初始数据很多,但是增幅较慢 | 地图数据 | 24 | | 枚举值 | 绝大多数场合 | 58 同城、饿了么 | 25 | | 日期分片 | 按照日期查找数据 | 日志数据 | 26 | | 自然月分片 | 按照日期查找数据 | 财务数据 | 27 | | 冷数据分片 | 冷热数据分离 | 订单数据 | 28 | 29 | - 枚举值:根据一些值决定路由到哪个分片上 30 | 31 | 比如 58 上浏览网站,需要先让你选择所在城市,然后出现相关的网站内容;招聘、租房等都是按照城市来分片的; 32 | 33 | - 日期分片: 34 | 35 | 可以按照天来分片,做数据统计和分析就比较方便; 36 | 37 | - 自然月分片:每个月的数据存到一个分片 38 | 39 | ## Mycat 性能参数 40 | 41 | 这些都在 Mycat 手册上有相关说明,这里介绍一些,其他的去手册上看 42 | 43 | - 每天 2 亿数据的实时查询案例(手册 239 页) 44 | - 物联网 26 亿数据的案例(手册 241 页) 45 | - 大型分布式零售系统案例(首次 241 页) 46 | 47 | ## 什么是全局表 48 | 49 | 在 Mycat 中,一种是全局表,一种是分片表。 50 | 51 | 数据字典表或则数据量不是很大的业务表,都可以定义成 **全局表**,在每个分片中的数据都是一样的。 52 | 53 | ```xml 54 | 55 |
56 |
57 | ``` 58 | 59 | 给虚拟表的 type 设置为 global,就是全局表了。 60 | 61 | ## 全局表的 SQL 路由 62 | 63 | - 查询语句: 64 | 65 | 由于所有分片的数据都是一样的,它会随机路由给一个分片执行 66 | 67 | - INSERT、DELETE、UPDATE 语句: 68 | 69 | 会路由给每个分片执行 -------------------------------------------------------------------------------- /docs/ali-new-retail/10/07.md: -------------------------------------------------------------------------------- 1 | # 避免跨分配表连接:父子表 2 | 3 | 全局表可以与任何分片表做连接。 4 | 5 | ## 跨分片的表连接 6 | 7 | 跨分片的表连接需要在网络中传输大量的数据,所以 **MyCat 不支持跨分片表连接**。 8 | 9 | 要实现跨分片表,需要把分片的数据收集到一个分片中执行,传输数据大,也不好实现。 10 | 11 | mycat 通过父子表解决一定场景下的分片表查询 12 | 13 | ## 父子表机制 14 | 15 | 两张都是用了水平气氛的数据表,要实现表连接查询,需要定义负责表关系。**父表数据切分到什么分片,子表的数据会切分到同样的分片。** 16 | 17 | ![image-20200621144637535](./assets/image-20200621144637535.png) 18 | 19 | 比如:客户表和缴费表,在业务上是先有客户,再有缴费。所以需要把客户和缴费,同一个人的路由到相同的分片中,就可以做表连接查询了。 20 | 21 | ## 配置父子表 22 | 23 | 父表可以有切分规则,但是子表不能配置切分规则。 24 | 25 | ```xml 26 | 27 | 28 | ... 29 |
30 | ``` 31 | 32 | table 属性 33 | 34 | - primaryKey:表主键列名称;是否被缓存的标志 35 | 36 | 使用了 primaryKey,会被 mycat 缓存数据,缓存值就是这个 key 37 | 38 | - rule:使用的数据切分规则 39 | 40 | childTable 属性: 41 | 42 | - primaryKey:和上面的是一样的 43 | 44 | - joinKey:规定的是子表中的字段 45 | - parentKey:规定的是父表中的字段 46 | 47 | joinKey 和 parentKey 定义了父子表用什么字段进行连接查询;类似于外键约束。在数据插入的时候,插入子表数据时,mycat 会去检查父表中是否有对应的 customer_id ,如果没有则会插入出错 48 | 49 | 这里在 t1 中增加这个父子表的定义 50 | 51 | ```xml 52 | 53 |
54 | 55 | 56 |
57 |
58 | ``` 59 | 60 | ## 父子表测试 61 | 62 | 配置文件完成之后,通过 9066 管理端口热加载配置文件 63 | 64 | ```sql 65 | reload @@config_all; 66 | ``` 67 | 68 | 在 t1 中创建数据表 69 | 70 | ```sql 71 | -- 客户表 72 | create table customer( 73 | id int unsigned primary key, 74 | name varchar(200) not null, 75 | city_id int unsigned not null 76 | )default charset=utf8; 77 | 78 | -- 缴费表 79 | create table payment( 80 | id int unsigned primary key, 81 | customer_id int unsigned not null, 82 | pay decimal(10,2) unsigned not null, 83 | create_time timestamp not null 84 | )default charset=utf8; 85 | ``` 86 | 87 | 插入测试数据 88 | 89 | ```sql 90 | -- 往两个分片中各插入了一条客户数据 91 | INSERT INTO `t1`.`customer`(`id`, `name`, `city_id`) VALUES (1, 'Scott', 10); 92 | INSERT INTO `t1`.`customer`(`id`, `name`, `city_id`) VALUES (2, 'Jack', 24); 93 | 94 | -- 往 payment 中插入了 3 条数据 95 | -- 客户 1 有两条缴费记录 96 | -- 客户 2 有一条缴费记录 97 | INSERT INTO `t1`.`payment`(`id`, `customer_id`, `pay`, `create_time`) VALUES (1, 1, 50.00, '2020-06-21 07:59:55'); 98 | INSERT INTO `t1`.`payment`(`id`, `customer_id`, `pay`, `create_time`) VALUES (2, 1, 99.00, '2020-06-21 07:59:39'); 99 | INSERT INTO `t1`.`payment`(`id`, `customer_id`, `pay`, `create_time`) VALUES (3, 2, 100.00, '2020-06-21 08:00:06'); 100 | ``` 101 | 102 | 那么现在去验证下,在第一个分片中是否存在一条客户为 Scott 的数据,和两条缴费数据。 -------------------------------------------------------------------------------- /docs/ali-new-retail/10/08.md: -------------------------------------------------------------------------------- 1 | # 全局主键 2 | 3 | 在数据库集群的场景下,使用数据库主键自增长,会产生重复主键记录。 4 | 5 | ![image-20200621170407068](./assets/image-20200621170407068.png) 6 | 7 | 在数据库集群环境中,应该使用中间件来生成主键值。 8 | 9 | Mycat 支持多种 **全局主键** 生成方式,其中最好的是 Zookeeper 方式。 10 | 11 | ## 本地文件方式 12 | 13 | Mycat 按照计数器的放生成自增长的主键值,计数器的参数被保存在文本文件中。 14 | 15 | 最大的缺点就是:无法与其他 Mycat 通信。比如你部署了主备,其中一个挂掉的时候,另外一个启动起来,无法获取到之前的主键参数。 16 | 17 | ![image-20200621170720454](./assets/image-20200621170720454.png) 18 | 19 | 这种方式只适合测试中使用; 20 | 21 | ## 数据库方式 22 | 23 | 和文件方式类似,只是把计数器的参数保存到数据库中。 24 | 25 | ![image-20200621170912726](./assets/image-20200621170912726.png) 26 | 27 | 缺点: 28 | 29 | - 如果是 pxc 集群:可能会产生一定的性能影响,因为是同步复制 30 | - 如果是 Replication 集群:如果没有同步成功,第一个 mycat 挂掉了,第二个立即启用,会造成主键重复。 31 | 32 | ## 本地时间戳方式 33 | 34 | MyCat 根据本地时间戳和机器 ID ,生成一个 18 位的主键值。 35 | 36 | 缺点:因为生成的主键值都是偶数,所以无法用在主键求模切分规则上 37 | 38 | ## Zookeeper 时间戳方式 39 | 40 | 利用 Zookeeper 生成时间戳主键值(64 位整数),主键字段必须使用 bigint 类型。 41 | 42 | 可以使用 Zookeeper 集群来保证高可用性。 43 | 44 | 但是如果使用时间戳,本地为什么做不到有奇数和偶数? 45 | 46 | ## 安装 Zookeeper 47 | 48 | 下载安装 Zookeeper 官方镜像 49 | 50 | ```bash 51 | docker pull zookeeper 52 | ``` 53 | 54 | 启动 Zookeeper 55 | 56 | ```bash 57 | docker run -d --name z1 58 | -p 2181:2181 59 | -p 3888:3888 60 | -p 2888:2888 61 | --net=swarm_mysql 62 | zookeeper 63 | ``` 64 | 65 | 实践练习 66 | 67 | ```bash 68 | [root@study ~]# docker run -d --name z1 -p 2181:2181 -p 3888:3888 -p 2888:2888 --net=swarm_mysql zookeeper 69 | bab947328f72d32f95728bf99ab02e2f47dd91f93360512316901283df52676a 70 | ``` 71 | 72 | ### 配置 Zookeeper 时间戳主键 73 | 74 | 编辑 `server.xml` 文件 75 | 76 | ```xml 77 | 3 78 | ``` 79 | 80 | 修改 `myid.properties` 文件 81 | 82 | ```bash 83 | loadZk=true 84 | zkURL=192.168.56.105:2181 85 | clusterId=mycat-cluster-1 86 | myid=mycat_fz_01 87 | clusterSize=1 88 | clusterNodes=mycat_fz_01 89 | #server booster ; booster install on db same server,will reset all minCon to 2 90 | type=server 91 | # boosterDataHosts=dataHost1 92 | ``` 93 | 94 | - clusterId:集群名称,可以自己规定 95 | - myid:mycat 主机名,也可以自己定义 96 | - clusterNodes:mycat 集群有几个节点组成,这里对应的是 myid 的值,多个用逗号分隔 97 | 98 | 这里配置 mycat 集群信息。我们这里只有一个 mycat,设置为一个。 99 | 100 | ### 测试全局主键 101 | 102 | 可以通过管理端口,热加载配置文件 103 | 104 | ```bash 105 | reload @@config_all; 106 | ``` 107 | 108 | 由于访问的是本机的 zk,所以不需要放开防火墙。 109 | 110 | 获取全局主键的 sql 语句为 111 | 112 | ```sql 113 | SELECT next value for MYCATSEQ_GLOBAL; 114 | -- 比如返回的主键 ID 是 7326346979595812993 115 | ``` 116 | 117 | ## 把全局主键应用到插入语句中 118 | 119 | 由于主键要求类型为 bigint,这里把 t2 中的 company 表的主键 ID 修改为 bigint 类型; 120 | 121 | 使用主键的插入语句如下 122 | 123 | ```sql 124 | INSERT INTO company ( id, name, city_id ) 125 | VALUES 126 | (next VALUE FOR MYCATSEQ_GLOBAL, "test", 411 ); 127 | ``` 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /docs/ali-new-retail/10/09.md: -------------------------------------------------------------------------------- 1 | # 总结 2 | 3 | 要点回顾 4 | 5 | - 搞懂了垂直切分与水平切分的区别;重要 6 | - 掌握了数据库集群负载均衡和读写分离;重要 7 | - 学习了 MyCat 常用的数据切分规则;重要 8 | - 掌握了 MyCat 独有的父子表机制;重要 9 | - 掌握了 MyCat 全局主键机制; 重要 -------------------------------------------------------------------------------- /docs/ali-new-retail/10/README.md: -------------------------------------------------------------------------------- 1 | # 分库分表的 N 种姿势 2 | 新零售数据库分库分表的N种姿势与容灾备份【「装逼」很适合】 3 | 4 | 本章直击「分库分表」与容灾备份,从水平切分到垂直切分,工作中可用于装逼,面试可稳住场面,强大的气场与自信也很重要。 5 | 6 | 涵盖:读写分离、全局表、常数据切分算法、切分后表连接面临问题、全局主键 N 种姿势,重点讲 Zookeeper 分布式全局主键。 7 | 8 | - [垂直切分与水平切分](./01.md) 9 | - [安装 MyCat](./02.md) 10 | - [配置 MyCat](./03.md) 11 | - [启动 MyCat](./04.md) 12 | - [Mycat 垂直/水平切分/全局表](./05.md) 13 | - [MyCat 路由规则](./06.md) 14 | - [避免跨分配表连接:父子表](./07.md) 15 | - [全局主键](./08.md) 16 | - [本章总结](./09.md) -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200618212254757.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200618212254757.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200618212452578.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200618212452578.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200618212715914.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200618212715914.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200618212937247.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200618212937247.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200618213540418.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200618213540418.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200618214243848.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200618214243848.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200618214534441.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200618214534441.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200618215047621.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200618215047621.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200618220204807.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200618220204807.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200618220337563.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200618220337563.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200620145805281.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200620145805281.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200620160426946.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200620160426946.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200620162209185.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200620162209185.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200620214923711.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200620214923711.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200620221957256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200620221957256.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200621144637535.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200621144637535.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200621150223525.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200621150223525.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200621170407068.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200621170407068.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200621170720454.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200621170720454.png -------------------------------------------------------------------------------- /docs/ali-new-retail/10/assets/image-20200621170912726.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/10/assets/image-20200621170912726.png -------------------------------------------------------------------------------- /docs/ali-new-retail/11/README.md: -------------------------------------------------------------------------------- 1 | # 集群环境下的新零售数据库与总结 2 | 3 | 本章也探讨下如何将新零售数据库迁移到集群环境中。 4 | 5 | ## 迁移新零售数据库到集群环境 6 | 7 | 如果是 **小型的新零售业务**,可以只 **选择水平切分**。如果是 **大中型的新零售业务**,可以兼顾 **垂直切分和水平切分** 8 | 9 | 本课是按照大型系统进行数据库设计的方案,**先按照业务划分出若干的子系统**,再去设计这些 **子系统应该使用什么样的数据库集群** 10 | 11 | ### 垂直切分方案 12 | 13 | ![image-20200621181612366](./assets/image-20200621181612366.png) 14 | 15 | 拆分成 5 个子系统: 16 | 17 | - 企业系统:企业管理系统, 18 | 19 | 管理员工、部门、角色、权限、财务等 20 | 21 | - 销售系统:线上线下的销售 22 | 23 | 商品表、订单表等 24 | 25 | - 售后系统: 26 | 27 | 购物评价、退换货等 28 | 29 | - 仓库系统:管理进销存的信息 30 | 31 | - 物流系统:快递信息跟踪由该系统支持 32 | 33 | 对于垂直切分,没有固定的答案,和业务规模、团队技术等相关,每个人的理解都不太一样。 34 | 35 | ### 创建逻辑库 36 | 37 | 以售后系统举例:由于售后系统的数据价值不是很高,使用 Replication 集群来保存数据。 38 | 39 | ![image-20200621181834358](./assets/image-20200621181834358.png) 40 | 41 | ### 映射逻辑库分片关系 42 | 43 | ```xml 44 | 45 | 46 | ``` 47 | 48 | 使用两个集群分片来存储。 49 | 50 | ### 数据库集群方案 51 | 52 | 什么样的子系统适合用什么样的方案,可以参考下下面的表格 53 | 54 | | 序号 | 系统名称 | 集群方案 | 55 | | :--: | :------: | ---------------- | 56 | | 1 | 企业系统 | Replication | 57 | | 2 | 销售系统 | PXC、Replication | 58 | | 3 | 售后系统 | Replication | 59 | | 4 | 仓库系统 | Replication | 60 | | 5 | 物流系统 | Replication | 61 | 62 | - 企业系统的数据库集群配置 63 | 64 | 企业系统的 **数据量和访问量并不是很大**,用一个 Replication 分片,然后 **都设置成全局表** 即可 65 | 66 | ![image-20200621182420663](./assets/image-20200621182420663.png) 67 | 68 | 最好配置两个主节点,这个知识点在后续的升级中讲解 69 | 70 | - 销售系统的数据库集群配置 71 | 72 | 销售系统中 **重要的数据 **需要切分存 **储到 PXC 分片**,非重要的切分存储在 Replication 分片。 73 | 74 | ![image-20200621182700872](./assets/image-20200621182700872.png) 75 | 76 | 对于分片的规模,需要看具体的数据规模、还需要做好冷热数据的归档,冷数据抽到 TokuDB 或 MongoDB 中 77 | 78 | - 售后系统的数据库集群配置 79 | 80 | 大多数的数据是 **数据量大的低价值的** 数据,所以可以采用 Replication 切分存储; 81 | 82 | ![image-20200621182853195](./assets/image-20200621182853195.png) 83 | 84 | - 仓库系统的数据库集群配置 85 | 86 | 仓库系统 **数据相对较少**,所以 **可以不使用水平切分**,仅 **使用一个 Replication 分片**,数据表都 **设计成全局表** 87 | 88 | ![image-20200621183014367](./assets/image-20200621183014367.png) 89 | 90 | - 物流系统的数据库集群配置 91 | 92 | 数据相对较多,可以采用 Replication 切分存储。 93 | 94 | 如快递已发出、到了转运地区,等一个包裹的物流数据就好多条; 95 | 96 | ![image-20200621183126068](./assets/image-20200621183126068.png) 97 | 98 | ## 课程总结 99 | 100 | 拓宽了数据库的技术视野 101 | 102 | ![image-20200621183333572](./assets/image-20200621183333572.png) 103 | 104 | 这里笔者就不记录回顾讲解了哪些细致的知识点了。 105 | 106 | 对于数据库集群底层的原理,这里没有讲解。可以去搜该老师的 PXC 集群课程观看。这里我们使用了别人/官方封装好的 Docker 镜像快速搭建起数据库集群,对于里面需要修改哪些配置文件之类的,镜像封装了细节。 107 | 108 | ## 后续课程升级内容 109 | 110 | - Docker 图形化界面 111 | 112 | - 封装 Replication 镜像 113 | 114 | - 分布式事务 115 | 116 | - ETL 中间件 117 | 118 | 经过垂直切分之后,无法做表连接查询,但是可以通过 ETL 中间件从多个数据源抽取相关数据 119 | 120 | ![image-20200621184056678](./assets/image-20200621184056678.png) 121 | 122 | 写程序时,面对这个结果集查询。 123 | 124 | -------------------------------------------------------------------------------- /docs/ali-new-retail/11/assets/image-20200621181612366.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/11/assets/image-20200621181612366.png -------------------------------------------------------------------------------- /docs/ali-new-retail/11/assets/image-20200621181834358.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/11/assets/image-20200621181834358.png -------------------------------------------------------------------------------- /docs/ali-new-retail/11/assets/image-20200621182420663.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/11/assets/image-20200621182420663.png -------------------------------------------------------------------------------- /docs/ali-new-retail/11/assets/image-20200621182700872.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/11/assets/image-20200621182700872.png -------------------------------------------------------------------------------- /docs/ali-new-retail/11/assets/image-20200621182853195.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/11/assets/image-20200621182853195.png -------------------------------------------------------------------------------- /docs/ali-new-retail/11/assets/image-20200621183014367.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/11/assets/image-20200621183014367.png -------------------------------------------------------------------------------- /docs/ali-new-retail/11/assets/image-20200621183126068.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/11/assets/image-20200621183126068.png -------------------------------------------------------------------------------- /docs/ali-new-retail/11/assets/image-20200621183333572.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/11/assets/image-20200621183333572.png -------------------------------------------------------------------------------- /docs/ali-new-retail/11/assets/image-20200621184056678.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/11/assets/image-20200621184056678.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/02.md: -------------------------------------------------------------------------------- 1 | # 使用 Portainer 管理 Docker 2 | 3 | Docker 的管理界面有很多,这里推荐 Portainer,下面是他的管理界面 4 | 5 | ![image-20200623215307022](./assets/image-20200623215307022.png) 6 | 7 | ## 开放 Dcoker 网络管理端口 8 | 9 | Portainer 之所以能管理 docker ,是因为它访问的是 Docker 网络管理端口,所以我们先放开。 10 | 11 | ```bash 12 | [root@study ~]# vi /etc/sysconfig/docker 13 | # 在配置文件末尾增加以下配置 14 | # 重要的就是这个端口,默认就是 2375 15 | OPTIONS='-Htcp://0.0.0.0:2375 -H unix:///var/run/docker.sock' 16 | # 配置之后,需要重新启动 docker 服务 17 | 18 | firewall-cmd --zone=public --add-port=2375/tcp --permanent 19 | firewall-cmd --reload 20 | 21 | [root@study ~]# systemctl restart docker 22 | ``` 23 | 24 | ## 安装 Portainer 25 | 26 | ```bash 27 | [root@study ~]# docker pull portainer/portainer 28 | # -H 参数:写的是宿主机上的 IP 和端口 29 | [root@study ~]# docker run -d -p 9000:9000 --name portainer portainer/portainer -H tcp://192.168.56.105:2375 30 | ``` 31 | 32 | 容器启动后,访问:http://192.168.56.105:9000/ 就能进入到管理界面了 33 | 34 | 进入到管理界面之后,里面的内容和前面学到的 images、volumes、containers 等是对应的,只要前面认真学过了,这里的图形界面实现我们之前的操作,基本上都没有问题了。 35 | 36 | 创建容器时分配硬件资源,在前面没有学习过,如下图,可以分配使用的内存、CPU 等 37 | 38 | ![image-20200623222239413](./assets/image-20200623222239413.png) -------------------------------------------------------------------------------- /docs/ali-new-retail/12/03.md: -------------------------------------------------------------------------------- 1 | # Binlog 日志文件的重要性 2 | 3 | Replication 集群原理就是利用 Binlog 日志进行同步数据,所以有必要了解。 4 | 5 | ## Binlog 日志文件 6 | 7 | binlog 日志文件记录了 **MySQl 执行的所有操作**,以及 **执行 SQL 语句消耗的时间**。 8 | 9 | 默认情况下是关闭的。 10 | 11 | ## 开启 binlog 日志 12 | 13 | 修改 mysql 配置文件,加上 log_bin 参数,重新启动 MySQL 服务 14 | 15 | ```bash 16 | ## 日志文件名称,可以随意起名 17 | log_bin = mysql_bin 18 | ``` 19 | 20 | 对于文件的切分存储,mysql 会自动做,后面搭建 Replication 集群时再演示。 21 | 22 | ## 误删除数据的闪回 23 | 24 | Binlog 日志文件的重要性作用,这里使用 误删除数据的闪回做例子讲解 25 | 26 | 执行了错误的 SQL 语句,误删除了记录,即便 **事物已经提交**,但是 **依然可以找回数据**,但是业务系统必须要停机(不能有新的数据写入) 27 | 28 | 可以使用 Python 程序从 binlog 日志中提取 SQL 语句,然后找到剔除错误的 SQL 语句,重新执行 binlog 日志中的 SQL 即可 29 | 30 | ## 误删除数据找回演示 31 | 32 | 笔者这里不去实操了。只记录下流程 33 | 34 | 需要一个权限的 binlog 日志,最好就是先把之前的删除掉,重新启动数据库。 35 | 36 | 然后执行一些插入数据的操作,再删除掉数据,再插入几行。 37 | 38 | 那么我们就要利用闪回工具找回被删掉的数据,并且新插入的还保留。 39 | 40 | ```sql 41 | -- 首先查看 binlogs 的路径 42 | SHOW MASTER LOGS 43 | 44 | -- 查询的结果,类似如下的显示 45 | -- 有多个 bin log 文件 46 | Log_name File_size 47 | mysql-bin.000001 177 48 | mysql-bin.000002 2996342 49 | mysql-bin.000003 734 50 | ``` 51 | 52 | 使用 binlog2sql 工具,找回 53 | 54 | ```bash 55 | python binlog2sql.py 56 | -uadmin -p'123456' # 用户名与密码 57 | -dflash # 逻辑库 58 | -t student # 数据表 59 | --start-file=‘mysql-bin.000001’ # 日志文件 60 | >/home/flash1.sql # 将解析的 sql 语句输出到哪个文件 61 | ``` 62 | 63 | 这个命令要对多个 binlog 日志进行解析,因为你不确定那些语句被记录在哪个文件上了 64 | 65 | ```bash 66 | python binlog2sql.py -uadmin -p'123456' -dflash -t student --start-file=‘mysql-bin.000001’>/home/flash1.sql 67 | 68 | python binlog2sql.py -uadmin -p'123456' -dflash -t student --start-file=‘mysql-bin.000002’>/home/flash2.sql 69 | ``` 70 | 71 | 解析出的 SQL 语句如下图所示 72 | 73 | ![image-20200623225211701](./assets/image-20200623225211701.png) 74 | 75 | 可以看到先插入了 4 条语句,然后更新了 2 条语句,再删除了 4 条语句,再插入了 4 条语句。包括还有创建表的语句。 76 | 77 | 找回数据就很简单了:将 delete 的那 4 条语句删除,把其他的语句重新执行一次,就找回来了 78 | 79 | -------------------------------------------------------------------------------- /docs/ali-new-retail/12/04.md: -------------------------------------------------------------------------------- 1 | # 主从同步原理 2 | 3 | ![image-20200627110238826](./assets/image-20200627110238826.png) 4 | 5 | - 主节点执行的查询语句都会记录在 binlog 中 6 | - 从节点监听主节点 binlog 文件,同步到自己的 relaylog 中 7 | - 从接待再执行 relaylog 中的 sql 语句 8 | 9 | 数据同步是单向的,其实就是看错读写分离的架构。主写,从读。 10 | 11 | ## 一主多从架构 12 | 13 | 通常来说,业务系统都是读多写少的,可以给主节点配置更的从节点。 14 | 15 | ![image-20200627111909836](./assets/image-20200627111909836.png) 16 | 17 | 但是如果从 **节点的数量超过了 3 个**,出现 **从节点数据同步跟不上主节点的写入**。 18 | 19 | 原因是因为:从点的过多,会消耗主节点的网络资源,导致数据同步变慢,解决方案是 **从节点分发数据** 20 | 21 | ## 从节点分发数据 22 | 23 | 解决主节点同步速度慢问题。合理的使用从节点充当中继节点,供给其他的更多的从节点数据同步 24 | 25 | ![image-20200627112021563](./assets/image-20200627112021563.png) 26 | 27 | 在实现上,其实从节点变成了他下面挂的从节点的主节点。 28 | 29 | ## 双主节点相互同步 30 | 31 | 在 Replication 集群中,主节点挂了,从节点不会自动成为主节点;为了实现主节点的高可用,实现双柱节点相互同步。 32 | 33 | ![image-20200627112755656](./assets/image-20200627112755656.png) 34 | 35 | 配置思路: 36 | 37 | 1. 左边作为主,右边作为从 38 | 2. 右边作为主,左边作为从 39 | 40 | 但是需要注意的一个问题是:还是 Replication 的一个弊端,是异步的同步数据,导致有可能其中一个并不能完全同步到数据。其实这个也没有什么好注意的。 Replication 就是有这个弊端。 41 | 42 | ## 删除原有的 Replication 集群 43 | 44 | REP 1 45 | 46 | | 虚拟机 | IP 地址 | 端口 | 容器 | 数据卷 | 47 | | :------: | :------------: | :--: | :----: | :----: | 48 | | docker-1 | 192.168.56.105 | 9003 | rn1(m) | rnv1 | 49 | | docker-2 | 192.168.56.107 | 9003 | rn2(s) | rnv2 | 50 | | docker-3 | 192.168.56.108 | 9003 | rn3(s) | rnv3 | 51 | 52 | REP 2 53 | 54 | | 虚拟机 | IP 地址 | 端口 | 容器 | 数据卷 | 55 | | :------: | :------------: | :--: | :----: | :----: | 56 | | docker-1 | 192.168.56.105 | 9004 | rn4(m) | rnv4 | 57 | | docker-2 | 192.168.56.107 | 9004 | rn5(s) | rnv5 | 58 | | docker-3 | 192.168.56.108 | 9004 | rn6(s) | rnv6 | 59 | 60 | 因为要搭建新的 Replication 集群,原来搭建的两组集群要删除:容器和数据卷也要删除 61 | 62 | ## 安装 MySQL 镜像 63 | 64 | 由于需要做双主,我们需要安装普通的 mysql 集群镜像,然后一步一步搭建出来。由于 PXC 集群采用的 mysql 是 5.7 版本的,我们这里也建议使用相同版本的 MySQL。后续通过 ETl 中间件抽取数据做表连接,就更加容易。 65 | 66 | ```bash 67 | # 这里安装的是官方的 mysql 镜像 68 | docker pull mysql:5.7.27 69 | docker tag mysql:5.7.27 mysql 70 | docker rmi mysql:5.7.27 71 | ``` 72 | 73 | ## 创建 MySQL 容器 74 | 75 | 创建的时候,名称和数据卷都是使用之前删掉的。 76 | 77 | ```bash 78 | docker run -d -p 9003:3306 --name rn1 79 | -e MYSQL_ROOT_PASSWORD=123456 80 | -v rnv1:/var/lib/mysql --privileged 81 | --net=swarm_mysql mysql 82 | ``` 83 | 84 | 这里没有指定主从节点的参数,需要容器启动后,我们去修改配置文件来实现。 85 | 86 | ```bash 87 | # 装完一台,先测试是否能连接上再开始 88 | [root@study ~]# docker run -d -p 9003:3306 --name rn1 -e MYSQL_ROOT_PASSWORD=123456 -v rnv1:/var/lib/mysql --privileged --net=swarm_mysql mysql 89 | ``` 90 | 91 | -------------------------------------------------------------------------------- /docs/ali-new-retail/12/README.md: -------------------------------------------------------------------------------- 1 | # 新零售数据库在双十一不 down 机的秘诀? 2 | 3 | 终点便是起点,这一次请带上逼格再战。本章将带你提高逼格,让你设计的数据库抗住性能压力,秒变高可用。 4 | 5 | - [MyCat 双机热备方案](./01.md) 6 | - [使用 Portainer 管理 Docker](./02.md) 7 | - [Binlog 日志文件的重要性](./03.md) 8 | - [主从同步原理](./04.md) 9 | - [高可用 Replication 集群](./05.md) -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200621211931122.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200621211931122.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200621213655845.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200621213655845.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200621225537824.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200621225537824.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200623215307022.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200623215307022.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200623222239413.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200623222239413.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200623225211701.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200623225211701.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200627110238826.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200627110238826.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200627111909836.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200627111909836.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200627112021563.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200627112021563.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200627112755656.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200627112755656.png -------------------------------------------------------------------------------- /docs/ali-new-retail/12/assets/image-20200627121618088.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/ali-new-retail/12/assets/image-20200627121618088.png -------------------------------------------------------------------------------- /docs/ali-new-retail/README.md: -------------------------------------------------------------------------------- 1 | # 阿里新零售数据库设计与实战 2 | 3 | 从 0 到 1 实战新零售,数据库设计与实现。 4 | 5 | - [开门见山](./01/) 6 | - [前置准备](./02/) 7 | - [新零售业务介绍](./02/01.md) 8 | - [前置知识与环境要求](./02/02.md) 9 | - [前导知识](./03/) 10 | - [安装/配置 MySQL 数据库](./03/01.md) 11 | - [如何看懂 ER 图](./03/02.md) 12 | - [MySQL 基础 - CRUD](./03/03.md) 13 | - [事务机制](./03/04.md) 14 | - [新零售数据结构设计](./04/) 15 | - [什么是 SPU/SKU](./04/01.md) 16 | - [设计品类表和参数表](./04/02.md) 17 | - [设计品牌和分类关系表](./04/03.md) 18 | - [设计产品表和商品表](./04/04.md) 19 | - [如何设计商品的库存?](./04/05.md) 20 | - [设计客户表](./04/06.md) 21 | - [设计购物卷表](./04/07.md) 22 | - [设计订单表](./04/08.md) 23 | - [设计员工与用户表](./04/09.md) 24 | - [设计快递表和退货表](./04/10.md) 25 | - [设计评价表](./04/11.md) 26 | - [设计供货商数据表](./04/12.md) 27 | - [设计采购与入库数据表](./04/13.md) 28 | - [总结](./04/14.md) 29 | - [常见问题与企业级解决方案-初级](./05/) 30 | - [主键用数字还是 UUID?](./05/01.md) 31 | - [在线修改表结构](./05/02.md) 32 | - [订单和流水号的区别](./05/03.md) 33 | - [逻辑删除还是物理删除](./05/04.md) 34 | - [千万记录,如何快速分页](./05/05.md) 35 | - [读多写少和读多写多](./05/06.md) 36 | - [删改数据如何避免锁表?](./05/07.md) 37 | - [常见问题与企业级解决方案-进阶](./06/) 38 | - [如何实现商品秒杀](./06/01.md) 39 | - [什么是存储过程?](./06/02.md) 40 | - [什么是函数?](./06/03.md) 41 | - [什么是触发器?](./06/04.md) 42 | - [为什么不要使用存储过程?](./06/05.md) 43 | - [如何避免偷换交易中的商品信息?](./06/06.md) 44 | - [如何抵御 XSS 攻击?](./06/07.md) 45 | - [常见问题与企业级解决方案-高阶](./07/) 46 | - [数据库/程序 缓存如何选?](./07/01.md) 47 | - [智能拆分订单](./07/02.md) 48 | - [中文分词技术](./07/03.md) 49 | - [本章总结](./07/04.md) 50 | - [新零售系统数据库性能调优](./08/) 51 | - [MySQL 压力测试](./08/01.md) 52 | - [SQL 语句的优化](./08/02.md) 53 | - [MySQL 参数优化](./08/03.md) 54 | - [MySQL 慢查询日志](./08/04.md) 55 | - [本章总结](./08/05.md) 56 | - [新零售系统数据库集群](./09/) 57 | - [数据库集群能解决什么问题?](./09/01.md) 58 | - [如何使用 Docker 虚拟机](./09/02.md) 59 | - [分布式 Docker 环境](./09/03.md) 60 | - [搭建 PXC 集群](./09/04.md) 61 | - [搭建 Replication 集群](./09/05.md) 62 | - [本章总结](./09/06.md) 63 | - [分库分表的 N 种姿势](./10/) 64 | - [垂直切分与水平切分](./10/01.md) 65 | - [安装 MyCat](./10/02.md) 66 | - [配置 MyCat](./10/03.md) 67 | - [启动 MyCat](./10/04.md) 68 | - [Mycat 垂直/水平切分/全局表](./10/05.md) 69 | - [MyCat 路由规则](./10/06.md) 70 | - [避免跨分配表连接:父子表](./10/07.md) 71 | - [全局主键](./10/08.md) 72 | - [本章总结](./10/09.md) 73 | - [集群环境下的新零售数据库与总结](./11/) 74 | - [新零售数据库在双十一不 down 机的秘诀?](./12/) 75 | - [MyCat 双机热备方案](./12/01.md) 76 | - [使用 Portainer 管理 Docker](./12/02.md) 77 | - [Binlog 日志文件的重要性](./12/03.md) 78 | - [主从同步原理](./12/04.md) 79 | - [高可用 Replication 集群](./12/05.md) 80 | -------------------------------------------------------------------------------- /docs/ali-new-retail/index.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | return [ 3 | '', 4 | '01/', 5 | { 6 | title: '前置准备', 7 | children: [ 8 | '02/', 9 | '02/01.md', 10 | '02/02.md' 11 | ] 12 | }, { 13 | title: '前导知识', 14 | children: [ 15 | '03/', 16 | '03/01.md', 17 | '03/02.md', 18 | '03/03.md', 19 | '03/04.md' 20 | ] 21 | }, { 22 | title: '新零售数据结构设计', 23 | children: [ 24 | '04/', 25 | '04/01.md', 26 | '04/02.md', 27 | '04/03.md', 28 | '04/04.md', 29 | '04/05.md', 30 | '04/06.md', 31 | '04/07.md', 32 | '04/08.md', 33 | '04/09.md', 34 | '04/10.md', 35 | '04/11.md', 36 | '04/12.md', 37 | '04/13.md', 38 | '04/14.md' 39 | ] 40 | }, { 41 | title: '常见问题与企业级解决方案-初级', 42 | children: [ 43 | '05/', 44 | '05/01.md', 45 | '05/02.md', 46 | '05/03.md', 47 | '05/04.md', 48 | '05/05.md', 49 | '05/06.md', 50 | '05/07.md' 51 | ] 52 | }, { 53 | title: '常见问题与企业级解决方案-进阶', 54 | children: [ 55 | '06/', 56 | '06/01.md', 57 | '06/02.md', 58 | '06/03.md', 59 | '06/04.md', 60 | '06/05.md', 61 | '06/06.md', 62 | '06/07.md' 63 | ] 64 | }, { 65 | title: '常见问题与企业级解决方案-高阶', 66 | children: [ 67 | '07/', 68 | '07/01.md', 69 | '07/02.md', 70 | '07/03.md', 71 | '07/04.md' 72 | ] 73 | }, { 74 | title: '新零售系统数据库性能调优', 75 | children: [ 76 | '08/', 77 | '08/01.md', 78 | '08/02.md', 79 | '08/03.md', 80 | '08/04.md', 81 | '08/05.md' 82 | ] 83 | }, { 84 | title: '新零售平台的数据库集群', 85 | children: [ 86 | '09/', 87 | '09/01.md', 88 | '09/02.md', 89 | '09/03.md', 90 | '09/04.md', 91 | '09/05.md', 92 | '09/06.md' 93 | ] 94 | }, { 95 | title: '分库分表的 N 种姿势', 96 | children: [ 97 | '10/', 98 | '10/01.md', 99 | '10/02.md', 100 | '10/03.md', 101 | '10/04.md', 102 | '10/05.md', 103 | '10/06.md', 104 | '10/07.md', 105 | '10/08.md', 106 | '10/09.md' 107 | ] 108 | }, 109 | '11/', 110 | { 111 | title: '升级内容', 112 | children: [ 113 | '12/', 114 | '12/01.md', 115 | '12/02.md', 116 | '12/03.md', 117 | '12/04.md', 118 | '12/05.md' 119 | ] 120 | } 121 | ] 122 | } 123 | -------------------------------------------------------------------------------- /docs/high-performance/01/01.md: -------------------------------------------------------------------------------- 1 | # MySQL 逻辑架构 2 | 3 | ![image-20200415143832875](./assets/image-20200415143832875.png) 4 | 5 | 以上架构图,要牢记,这有助于深入理解 MySQL 服务器 6 | 7 | - 第一层:链接处理 8 | 9 | 大多数基于网络的客户端/服务器工具等都有类似的架构。比如链接处理、授权认证、安全等 10 | 11 | - 第二层:大多数的核心服务功能 12 | 13 | 包括查询解析、分析、优化、缓存以及所有的内置函数(如:日期、时间、数学和加密函数),所有跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等 14 | 15 | - 第三层:存储引擎 16 | 17 | 负责 MySQL 中数据的存储和提取。和 Linux 下文件系统一样,每个存储引擎都有他的优势和劣势。服务器通过 API 与存储引擎进行通信,这些接口屏蔽了不同存储引擎之间的差异。 18 | 19 | 存储引擎 API 包含十几个底层函数,用于执行诸如 「开始一个事物」或「根据主键提取一行记录」等操作。单存储引擎不会去解析 SQL(InnoDB 是一个列外,它会解析外键定义,MySQL 服务器本身没有实现该功能),不同存储引擎之间也不会相互通信,而只是简单的响应上层服务器的请求 20 | 21 | ## 连接管理与安全性 22 | 23 | 每个客户端链接都会在服务器进程中分配一个线程,这个连接的查询只会在这个单独的线程中执行。MySQL 5.5 或更新版本提供了一个 API,支持线程池(Thread-Pooling)插件,可以使用线程池中少量的线程来服务大量的连接。 24 | 25 | 当客户端连接到 MySQL 服务器时,服务器对其进行认证。基于用户名、原始主机信息和密码(可选 SSL 方式连接)。一旦客户端连接成功,服务器会继续验证客户端是否具有执行某个特定查询的权限(如,是否运行对某个表执行 select 语句) 26 | 27 | ## 优化与执行 28 | 29 | MySQL 会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重写查询、决定表的读取顺序,以及选择合适的索引等。用户可以通过特殊的关键字提示(hint) 优化器,影响它的抉择过程。也可以请求优化器解释(explain)优化过程的各个因素,使用户可以知道服务器是如何进行优化抉择的,并提供一个参考基准,便于用户重构查询和 schema、修改相关配置,使应用尽可能高效运行。 第 6 章详细讨论 30 | 31 | 优化器并不关心表使用的是什么存储引擎,但存储引擎对于优化查询是有影响的。优化器会请求存储引擎提供容量或某个具体操作的开销信息,以及表数据的统计信息等。例如,某些存储引擎的某种索引,可能对一些特定的查询有优化。关于索引与 schema 的优化请参考第 4、5 章 32 | 33 | 对于 SELECT 语句,在解析查询之前,服务器会先检查查询缓存(Query Cache),如果命中,服务器就不再执行查询解析、优化和执行的整个过程,而直接返回缓存中的结果集。第 7 章详细讨论 34 | -------------------------------------------------------------------------------- /docs/high-performance/01/02.md: -------------------------------------------------------------------------------- 1 | # 并发控制 2 | 3 | 只要有多个查询在同一时刻修改数据,就会产生并发控制问题,本章目的是讨论 MySQL 在两个层面的并发控制:服务器层与存储引擎层。由于该话题是一个庞大的话题,本章只简要的讨论 MySQL 如何控制并发读写 4 | 5 | 比如文件写入,两个线程对同一个文件执行写入操作,数据就有可能产生混乱,那么就会利用锁(lock)来防止数据损坏,但是不支持并发处理了,在任意时刻只有一个线程可以操作该文件 6 | 7 | ## 读写锁 8 | 9 | 多个线程从文件读取数据就没有问题,因为读取不会修改数据,但是一个读取,一个修改,这也会导致读取到不一致的数据,所以为了安全起见,即使读取也需要特别注意 10 | 11 | 如果把上述案例中的文件当成数据库中的一张表,把数据当成表中的一行记录,很容易看出,会存在同样的问题。 12 | 13 | 解决这类经典问题的方法就是并发控制,通过共享锁(shared lock)和排他锁(exclusive locke),也叫读锁(read lock)和写锁(write) 14 | 15 | 先不讨论锁的具体实现细节,概念如下: 16 | 17 | - 读锁:是共享的(互不阻塞的),多个客户在同一时刻可以同时读取同一个资源,互不干扰 18 | - 写锁:是排他的,会阻塞其他的写锁和读锁。只有这样才能确保在给定的时间里,只有一个用户能执行写入,并防止其他用户读取正在写入的同一资源 19 | 20 | 在实际的数据库系统中,每时每刻都在发生锁定 21 | 22 | ## 锁粒度 23 | 24 | 一种提高共享资源并发性的方式是让锁定对象更有选择性,尽量只锁定需要修改的部分数据。任何时候,在给定的资源上,锁定的数据量越少,则系统的并发程度越高,只要不相互发生冲突 25 | 26 | 那么问题来了,管理锁也需要消耗资源,如获锁、检查锁是否已经解除、释放锁等,都会增加系统的开销。更多的时间来管理锁,而不是用在存取数据上,这会导致系统性能下降,这需要一个权衡 27 | 28 | 在锁的开销和数据的安全性之间寻求平衡,这就是锁策略。大多数商业数据库系统没有提供更多的选择(策略),一般在表上施加 **行级锁(row-level lock)**,并以各种复杂的方式来实现,使锁比较多的情况下尽可能提供更好的性能 29 | 30 | MySQL 则提供了多种选择。每种存储引擎都可以实现自己的锁策略和锁的粒度。将锁粒度固定在某个级别,可以在某些特定的应用场景提供更好的性能,但同时会失去对另外一些应用场景的良好支持。而 MySQL 支持多个存储引擎的架构,则让用户能有更多的选择。下面将介绍两种最重要的锁策略 31 | 32 | ### 表锁(table lock) 33 | 34 | 表锁是 MySQL 中最基本的锁策略,并且是开销最小的策略。顾名思义,当一个用户在对表进行写操作(插入、删除、更新等),就会锁定整张表,这会阻塞其他用户对该表的所有读写操作。读锁之间是不相互阻塞 35 | 36 | 在特定场景中,表锁也可能有良好的性能。比如:READ LOCAL 表锁支持某些类型的并发写操作。另外,写锁比读锁有更高的优先级,因此一个写锁清秋可能会被插入到读锁队列的前面(反之,读锁则不能插入到写锁前面) 37 | 38 | 尽管存储引擎可以管理自己的锁,但是 MySQL 会使用各种有效的表锁来实现不同的目的。比如,服务器会为诸如 ALTER TABLE 之类的语句使用表锁,而忽略存储引擎的锁机制 39 | 40 | ### 行级锁(row lock) 41 | 42 | 行级锁可以最大程度的支持并发处理,同时也带来了最大的锁开销。 43 | 44 | 在 InnoDB 和 XtraDB,以及其他一些存储引擎中实现了行级锁,而且只在存储引擎层实现。服务器层完成不了解存储引擎中的锁实现 45 | 46 | 在本章的后续内容以及全书中,所有的存储引擎都以自己的方式显现了锁机制 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/high-performance/01/04.md: -------------------------------------------------------------------------------- 1 | # 多版本并发控制 2 | 3 | MySQL 的大多数事务型存储引擎实现都不是简单的行级锁。为了提升并发性能,一般都同时实现了多版本并发控制(MVCC)。Oracle、PostgreSQL 等也实现了 MVCC,但各自实现机制不同,因为 MVCC 没有一个统一的实现标准。 4 | 5 | 可以认为 MVCC 是行级锁的变种,但在很多情况下避免了加锁操作,因此开销更低。虽然实现机制不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。 6 | 7 | MVCC 的实现,是 **通过保存数据在某个时间点的快照来实现的**。也就是说,不管需要执行多长时间,每个事物看到的数据都是一致的。根据事物开始的时间不同,每个事物对同一张表,同一时刻看到的数据可能是不一样的。这句话目前笔者就不能完全理解,这个需要熟悉之后,才会理解 8 | 9 | 前面说到不同存储引擎的 MVCC 实现是不同的,,典型的有乐观锁(optimistic)并发控制和悲观(pessimistic)并发控制 10 | 11 | InnoDB 的 MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。一个保存了行的创建时间,一个保存行的过期时间(或删除时间)。存储的不是实际的时间值,而是系统版本号(system version number)。每开始一个新的事物,系统版本号都会自动递增。事物开始时刻的系统版本号会作为事物的版本号,用来和查询到的每行记录的版本号进行比较。下面看一下再 REPEATTABLE READ 隔离级别下,MVCC 具体是如何操作的 12 | 13 | - SELECT:会根据以下两个条件检查每行记录: 14 | 15 | - InnoDB 只查找版本早于当前事物版本的数据行(行的系统版本号小于或等于事物的系统版本号),这可以 **确保事物读取的行,要么是在事务开始前已经存在的,要么是事物自身插入或则修改过的**。 16 | - 行的删除版本要么未定义,要么大于当前事物版本号。这可以 **确保事物读取到的行,在事物开始之前未被删除**。 17 | 18 | - INSERT 19 | 20 | InnoDB 为新插入的每一行保存当前系统版本号作为行版本号 21 | 22 | - DELETE 23 | 24 | InnoDB 为删除的每一行保存当前系统版本号作为行删除标识 25 | 26 | - UPDATE 27 | 28 | InnoDB 为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为删除标识 29 | 30 | 保存这两个额外的系统版本号,使大多数读操作都可以不同加锁。使得读取数据操作很简单,性能很好,也能保证读取到符合标准的行。不足的是需要额外的存储空间和更多的行检查工作、额外的维护工作 31 | 32 | MVCC 只在 REPEATABLE READ 和 READ COMMITTED 两个级别下工作。其他两个级别不兼容(MVCC 没有正式的规范,由各个存储引擎实现决定),因为 READ UNCOMMITTED 总是读取最新的数据行,而 SERIALIZABLE 则会对所有读取的行都加锁 33 | 34 | 疑问:笔者这里没有想明白,是否是 MYSQL 的数据行,与 elasticsearch 类似?是不可变的,是通过标记删除旧的数据,让新的数据生效的机制? 35 | 36 | -------------------------------------------------------------------------------- /docs/high-performance/01/06.md: -------------------------------------------------------------------------------- 1 | # MySQL 时间线(Timeline) 2 | 3 | 在选择 MySQL 版本的时候,了解下版本的变迁历史是有帮助的。 4 | 5 | - 版本 3.23 (2001) 6 | 7 | 一般认为该版本是 MySQL 真正「诞生」时刻,开始获得广泛使用。在该版本中,MySQL 依然只是一个在平面文件(Flat File)上实现了 SQL 查询的系统。 8 | 9 | 但一个重要的改进是引入了 MyISAM 代替了老旧而有诸多限制的 ISAM 引擎。由于 InnoDB 太新,没有默认包含在发布的二进制发行版中。所以,要使用 InnoDB 必须手工编译。 10 | 11 | 还引入了全文索引和 **复制**,复制是 MySQL 成为互联网应用的数据库系统的关键性(killer feature) 12 | 13 | - 版本 4.0(2003) 14 | 15 | 支持新的语法,比如 **UNION** 和多表 **DELETE** 语法。 重写了复制,在备库使用了两个线程来实现复制,避免了之前一个线程做所有复制工作的模式下任务切换导致的问题。 16 | 17 | InnoDB 成为标准配备,包括了全部的特性:行级锁、外键等。 18 | 19 | 还引入了查询缓存(自那以后这部分改动不大),同时还支持通过 SSL 进行连接 20 | 21 | - 版本 4.1(2005) 22 | 23 | 引入了更多新的语法,比如子查询和 `INSERT ON DUPLICATE KEY UPDATE`。 开始支持 UTF-8 字符集。支持新的二进制协议和 prepared 语句。 24 | 25 | - 版本 5.0(2006) 26 | 27 | 出现了一些「企业级」特性:视图、触发器、存储过程和存储函数。老的 ISAM 引擎代码被彻底移除,同时引入了新的 Federated 等引擎。 28 | 29 | - 版本5.1(2008) 30 | 31 | Sum 收购 MySQL AB 以后发布的首个版本,研发时间长达 5 年。引入了分区、基于行的复制,以及 plugin API(包括可插播存储引擎的 API)。移除了 BerkeyDB 引擎,这是 MySQL 最早的事物存储引擎。其他的如 Federated 引擎也将被放弃。同时 Oracle 收购的 InnoDB Oy 发布了InnoDB plugin。 32 | 33 | - 版本 5.5(2010) 34 | 35 | Oracle 收购 Sun 以后发布的首个版本。主要改善集中在性能、扩展性、复制、分区、对微软 windows 系统的支持,以及一些其他方面。 InnoDB 成为默认的存储引擎。更多的一些遗留特性和不建议使用的特性被移除。增加了 PERFORMANCE_SCHEMA 库,包含了一些可测量的性能指标的增强。增加了复制、认证和审计 API。 半同步复制(semisynchronous replication)插件进入实用阶段。Oracle 还在 2011 年发布了商用的认证插件和线程池(thread pooling)。 InnoDB 在架构方面也做了较大的改进,比如多个子缓冲池(buffer pool) 36 | 37 | - 版本 5.6(还未发布) 38 | 39 | 包含一些重大更新。比如多年来首次对查询优化器进行大规模的改进,更多的插件 API(如全文索引),复制的改进、以及 PERFORMANCE_SCHEMA 库增加了更多的性能指标。InnoDB 团队也做了大量的改进工作。 40 | 41 | MySQL 5.5 主要着重在基础部分的改进和加强,引入了部分新特性。而 MySQL 5.6 则在 5.5 的基础上提升服务器的开发和性能。 42 | 43 | - 版本 6.0(已取消) 44 | 45 | 传说中拥有大量的新特性,包括在线备份、服务器层面对所有存储引擎的外键支持,以及子查询的改进和线程池。后来该版本被取消,在 5.4 继续开发,最后发布时变成版本 5.5。 其中很多特性的代码出现在 5.5 和 5.6 中 46 | 47 | 简单总结下 MySQL 的发展史:早期的 MySQL 是一种破坏性创新,有诸多限制,并且很多功能是二流的。但是他的特性支持和较低的使用成本,使得其成为快速增长的互联网时代的杀手级应用。在 5.x 版本引入了企业级特性,但是不算成功,bug 较多,直到 5.0.50 以后才算稳定。 版本 5.0 和 5.1 发布都延期了许多时日,而且被 Sun 和 Oracle 收购。5.5 版本可以说是 MySQL 历史上质量最高的版本。5.6 也承诺在功能和性能方面将有显著的提升。 48 | 49 | 提到性能,下面尝试设计了多个测试方案来尽量保证在不同版本中的基准一致,并为此做了很多努力,下面显示了在服务器层面不同并发下的每秒事物的测试结果: 50 | 51 | ![image-20200506183846443](./assets/image-20200506183846443.png) 52 | 53 | 上表数据,以图方式展示为 54 | 55 | ![image-20200506183914938](./assets/image-20200506183914938.png) 56 | 57 | 在解释结果之前,介绍下测试环境: 58 | 59 | - 机器 Cisco UCS C250 60 | - 两颗 6 核 CPU ,没核支持 2 个线程 61 | - 内存 353GB 62 | - 测试的数据集是 2.5GB,所以 MySQL 的 buffer pool 设置为 4GB。 63 | - 采用 SysBench 的 read-only 只读测试进行压测,并采用 InnoDB 存储引擎 64 | - 所有的数据都可以放入内存,因此 CPU 密集型(Cpu-bound)的测试 65 | - 每次测试持续 60 分钟,每 10 秒获取一次性吞吐量的结果 66 | - 前 900 秒用于预热数据,以避免预热时的 I/O 影响测试结果 67 | 68 | 现在来看结果,有两个很明显的趋势: 69 | 70 | 1. InnoDB Plugin 的版本:在高并发的时候性能明显更好 71 | 72 | 2. 新的版本在单线程的时候性能比旧版本更差。 73 | 74 | 这只是一个非常简单的只读测试,新版本的 SQL 语法更复杂,针对复杂查询增加了很多特性和改进,这对简单查询可能带来了更多的开销。 75 | 76 | 一般来说,新版本在复杂场景时性能有更多的优化,尤其是高并发和大数据集的情况下。 77 | 78 | 那么该如何选择版本呢?这更多的取决于业务需求而不是技术需求。理想情况下当然是版本越新越好。 -------------------------------------------------------------------------------- /docs/high-performance/01/07.md: -------------------------------------------------------------------------------- 1 | # MySQL 的开发模式 2 | 3 | 它的开发过程和发布模型逐渐稳定下来。在定期发布的新里程碑开发版本中,会包含即将在下一个 GA(Generally Available 通常可用的版本,也意味着达到了满足生产环境中使用的质量标准) 版本发布的新特性,这样做是为了测试和获得反馈,但是不要用在生产环境中。最终,Oracle 会将稳定的特性打包发布一个新的 GA 版本。 4 | 5 | MySQL 依然遵循 GPL 开源协议,全部的源代码(除了商业版本的插件支持)都会放开给社区。MySQL AB 曾经尝试过不同版本的策略,但是遇到付费用户遇到问题无法从社区的测试和反馈中获得好处。不受企业用户的欢迎,所以后来被 Sun 废除了。 6 | 7 | 现在 Oracle 为付费用户单独提供了一些服务器插件,而 MySQL 本身还是遵循开源模式。 8 | 9 | 插件模式很重要,例如:如果 Oracle 将 InnoDB 的全文索引功能以 API 的方式实现,那么就可能以同样的 API 实现 Sphinx 或则 Lucene 的插件,这可能对一些用户更有用。服务器内部的 API 设计也很干净,这对于提升代码质量非常有帮助。 -------------------------------------------------------------------------------- /docs/high-performance/01/08.md: -------------------------------------------------------------------------------- 1 | # 总结 2 | 3 | MySQL 拥有分层的架构。上层是服务器层的服务和查询执行引擎,下层是存储引擎。虽然有很多不同作用的插件 API,但存储引擎 API 是最重要的。如果能理解 MySQL在存储引擎和服务层之间处理查询时如何通过 API 来回交互,就能抓住 MySQL 的核心基础架构的精髓。 4 | 5 | MySQL 最初基于 ISAM 构建(后来被 MyISAM 取代),后续添加了更多的存储引擎和事物的支持。 6 | 7 | 存储引擎 API 的架构也也有一些缺点。可选择的存储引擎很多,有时候并非是好事。InnoDB 对于 95% 以上的用户来说都是最佳选择,所以其他的存储引擎可能只是让事情变得复杂难搞,当然也不用否认某些情况下某些存储引擎能更好的满足需求。 8 | 9 | Oracle 一开始收购了 InnoDB,之后又收购了 MySQL,InnoDB 和 MySQL 服务器之间可以更快的协同发展。MySQL 依然基于 GPL 协议开放全部的源代码,MySQL 正在变得越来越可扩展和有用。 -------------------------------------------------------------------------------- /docs/high-performance/01/README.md: -------------------------------------------------------------------------------- 1 | # MySQL 架构与历史 2 | 3 | MySQL 的架构可以在多种不同的场景中应用,并发挥好的作用,但同时也会带来一点选择上的困难。 4 | 5 | 为了充分发挥 MySQL 的性能并顺利的使用,就必须理解它的设计。它最最重要、最与众不同的特性是他的存储引擎架构,将查询处理(Query Processing)及其他系统任务(Server Task)和数据的存储、提取相分离。这种处理和存储分离的设计可以在使用时根据性能、特性,以及其他需求来选择数据存储方式,很灵活 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/high-performance/01/assets/image-20200415143832875.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/01/assets/image-20200415143832875.png -------------------------------------------------------------------------------- /docs/high-performance/01/assets/image-20200506183846443.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/01/assets/image-20200506183846443.png -------------------------------------------------------------------------------- /docs/high-performance/01/assets/image-20200506183914938.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/01/assets/image-20200506183914938.png -------------------------------------------------------------------------------- /docs/high-performance/02/01.md: -------------------------------------------------------------------------------- 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 | - RAID 5 还是 RAID 10 更适合当前的系统? 30 | 31 | - 如果从 ATA 硬盘升级到 SAN 存储,对于随机写性能有什么帮助? 32 | - Linux 2.4 内核比 2.6 内核可扩展性更好吗? 33 | - 升级 MySQL 的版本能改善性能吗? 34 | - 为当前的数据采用不同的存储引擎会有什么效果? 35 | 36 | 诸如此类问题都可以通过专门的基准测试来获得答案。 37 | 38 | - 证明新采购的设备是否配置正确。 39 | 40 | 上述已经说过了,通过数据说话,比什么都重要。 41 | 42 | 基准是的一个主要问题在于 **不是真实的压力测试**。基准测试施加给系统的压力相对真实压力来说,通常比较简单。真实压力是不可预期而且变化多端的,有时候情况会过于复杂难以解释。所以使用真实压力测试,可能难以从结果中分析出确切的结论。 43 | 44 | 基准是的压力和真实压力在哪些方面不同?有很多因素会影响基准测试。 45 | 46 | 如:数据量、数据和查询的分布,最重要的一点还是 **基准测试通常要求尽可能快的执行完成**,所以经常给系统造成过大的压力。在很多案例中,我们都会调整给测试工具的最大压力,以在系统可以容忍的压力阀值内尽可能快的执行测试,这对于 **确定系统的最大容量** 非常有帮助。然而大部分压力测试工具不支持对压力进行复杂的控制。务必要记住,测试工具自身的局限也会影响到结果的有效性。 47 | 48 | 使用基准测试进行 **容量规划** 也要掌握技巧,不能只根据测试结果做简单的推断。 49 | 50 | 例如:假设想知道使用新数据库服务器后,系统能够支撑多大的业务增长。首先对源系统进行基准测试,然后对新系统做测试,结果发现新系统可以支持原系统 40 倍的 TPS(每秒事物数),这时候就不能简单的推断说新系统一定可以支持 40 倍的业务增长。这是因为在业务增长的同时,系统的流量、用户、数据以及不同数据之间的交互都在增长,他们不可能都有 40 倍的支撑能力,尤其是相互之间的关系。而且当业务增长到 40 倍时,应用本身的设计也可能已经随之改变。可能有更多的新特性会上线,其中某些特性可能对数据库造成的压力远大于原有功能。而这些压力、数据、关系和特性的变化都很难模拟,所以他们对系统的影响也很难评估。笔者总结:至少在当下,是新系统是比旧系统提升高很多。 51 | 52 | **结论就是:** 我们只能进行大概的测试,来确定系统大致的余量有多少。当然也可以做一些真实压力测试(和基准测试有区别),但在构造数据集和压力的时候要特别小心,而且这样就不再是基准测试了。**基准测试要尽量简单直接**,结果之间容易相互比较,成本低且易于执行。尽管有诸多限制,基准测试还是非常有用的(只要搞清楚测试的原理,并且了解如何分析结果所代表的意义)。 53 | 54 | ## 笔者总结 55 | 56 | 简单说:真实压力测试充满不稳定性和预估性,很难进行分析。而使用基准测试能在相同的条件下,对某项存疑进行验证。所以:**基准测试要尽量简单直接**,结果之间容易相互比较,成本低且易于执行; -------------------------------------------------------------------------------- /docs/high-performance/02/04.md: -------------------------------------------------------------------------------- 1 | # 基准测试工具 2 | 3 | 没有必要开发资金的基准测试系统,除非现有的工具确实无法满足需求。下面介绍一些可用的工具 4 | 5 | ## 集成式测试工具 6 | 7 | 已有额集成测试式工具有: 8 | 9 | ### ab 10 | 11 | ab 是 Apache HTTP 服务器基准测试工具。可用测试 HTTP 服务器每秒最多可以处理多少请求。如果测试的是 web 应用服务,这个结果可以转换成整个应用每秒可以满足多少请求。 12 | 13 | 是个非常简单的工具,用途也有限,只能针对单个 URL 进行尽可能的压力测试。 14 | 15 | ### http_load 16 | 17 | 概念上和 ab 类似,也被设计为对 web 服务器进行测试,比 ab 要更加灵活,可以通过一个输入文件提供多个 URL。它会在这些 URL 中随机选择进行测试。也可以定制 http_load,使其按照时间比率进行测试,而不仅仅是测试最大请求处理能力 18 | 19 | ### JMeter 20 | 21 | 是一个 Java 应用恒旭,可以加载其他应用并测试其性能。虽然是用来测试 web 应用的,但也可以用于测试诸如 FTP 服务器,或则通过 JDBC 进行数据库查询测试。 22 | 23 | 它比 ab 或 http_load 要复杂得多。例如: 24 | 25 | - 它可以通过控制预热时间等参数,更加灵活的模拟真实用户的访问。 26 | - 有绘图接口(带内置的图形化处理的功能) 27 | - 可以对测试进行记录,然后离线重演测试结果 28 | 29 | ## 单组件测试工具 30 | 31 | 有一些有用的工具可以测试 MySQL 和基于 MySQL 的系统性能。后续介绍如何利用这些工具进行测试 32 | 33 | ### mysqlslap 34 | 35 | mysqlslap 可以模拟服务器的负载,并输出计时信息。它包含在 MySQL 5.1 的发型包中。测试时可以执行并发连接数,并指定 SQL 语句(可以在命令行上执行,也可以把 SQL 语句写入到参数文件中)。如果没有指定 SQL 语句,它会自动生成查询 schema 的 SELECT 语句 36 | 37 | ### MySQL Benchmark Suite(sql-bench) 38 | 39 | 在 MySQL 的发行包中也提供了一款自己的基准测试套件,可以用于在不同数据库服务器上进行比较屙屎。它是单线程的,主要用于测试服务器执行查询的速度。结果会显示那种类的操作在服务器上执行得更快 40 | 41 | 该测试套件的主要好处是包含了大量预定义的测试,容易使用,所以可以很轻松的用于比较不同存储引擎或则不同配置的性能测试。也可应用于高层次测试,比较两个服务器的总体性能。当然也可以只执行预定义的测试子集(例如只测试 UPDATE 的性能)。这些测试大部分是 CPU 密集型的,但也有短时间的测试需要大量的磁盘 I/O 操作 42 | 43 | 该套件最大的缺点主要有:单用户模式,测试的数据集很小且用户无法使用指定的数据,并且同一个测试多次运行的结果可能会相差很大。因为是单线程且串行执行的,所以无法测试多 CPU 的能力,只能用于比较单 CPU 服务器的性能差别。使用该套件测试数据库服务器还需要 Perl 和 BDB 的支持 44 | 45 | ### Super Smack 46 | 47 | 是一款用于 MySQL 和 PostgrSQL 的基准测试工具,可以提供压力测试和负载生成。这是一个复杂而强大的工具,可以模拟多用户访问,可以加载测试数据到数据库,并支持使用随机数据填充测试表。测试定义在 「smack」文件中,smack 文件使用一种简单的语法定义测试的客户端、表、查询等测试要素 48 | 49 | ### Database Test Suite 50 | 51 | 是由开源软壳开发实验室设计的,发布在 SourceForge 网站上,是一款类似某些工业标准测试的测试工具集,例如由事物处理性能委员会(TPC)制定的各种标准。特别值得一提的是,其中的 dbt2 就是一款免费的 TPC-C OLTP 策测试工具。之前本书作作者经常使用该工具,不过现在已经使用自己研发的专用于 MySQL 的测试工具替代了 52 | 53 | ### Perconas TPCC-MySQL Tool 54 | 55 | 类似 TPC-C 的基准测试工具集,其中有部分是专门为 MySQl 测试开放的。在评估大鸭梨下 MySQL 的一些行为时,经常会利用这个工具进行测试(简单的测试,一般会采用 sysbench 替代) 56 | 57 | ### sysbench 58 | 59 | 是一款多线程系统压测工具。可以根据影响数据库服务器性能的各种因素来评估系统的性能。 60 | 61 | 例如,可以用来测试文件 I/O、操作系统调度器、内存分配和传输速度、POSIX 线程,以及数据库服务器等。支持 Lua 脚本语言,Lua 对于各种测试场景的设置可以非常灵活。 62 | 63 | sysbench 是我们非常喜欢的一种全能测试工具,支持 MySQL、操作系统和硬件的硬件测试。 64 | 65 | ### MySQL 的 `BENCHMARK()`函数 66 | 67 | MySQL 有一个内置的 `BENCHMARK()` 函数,可以测试某些特定操作的执行速度。参数可以是需要执行的次数和表达式。表达式可以是任何的标量表达式,比如返回值是标量的子查询或则函数。该函数可以很方便的测试某些特定操作的性能,比如通过测试可以发现 `MD5()` 函数比 `SHA1()` 函数要快 68 | 69 | ```sql 70 | SET @input := 'hello world'; 71 | -- 输出都是 0. 72 | SELECT BENCHMARK(1000000,MD5(@input)); 73 | 1 row in set (2.78 sec) 74 | 75 | SELECT BENCHMARK(1000000,SHA1(@input)); 76 | 1 row in set (3.50 sec) 77 | ``` 78 | 79 | 执行返回值永远是 0,可以通过客户端返回的时间来判断执行的时间。要清楚原理,否则容易误用。 80 | 81 | 该函数只是简单的返回服务器执行表达式的时间,而不会涉及分析和优化的开销。而且表达式必须像这个列子一样包含用户定义的变量,否则多次执行同样的表达式会因为系统缓存命中而影响结果。 82 | 83 | 它不适合用来做真正的基准测试,因为很难理解真正要测试的是什么,而且测试的只是整个执行周期中的一部分环节。 84 | -------------------------------------------------------------------------------- /docs/high-performance/02/README.md: -------------------------------------------------------------------------------- 1 | # MySQL 基准测试 2 | 3 | 基准测试(benchmark)是 MySQL **新手** 和 **专家** 都需要 **掌握** 的一项基本技能。 4 | 5 | 简单的说,基准测试时针对系统设计的一种 **压力测试**。通常的目标是为了掌握系统的行为,也也有其他原因,如重现某个系统状态,或则是做新硬件的可靠性测试。 6 | 7 | 本章将讨论: 8 | 9 | - MySQL 和基于 MySQL 的应用的基准测试的重要性 10 | - 策略和工具 11 | - sysbench:非常优秀的 MySQL 基准测试工具 -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507135121390.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507135121390.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507153735711.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507153735711.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507154740314.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507154740314.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507155740725.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507155740725.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507165234295.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507165234295.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507165314790.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507165314790.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507165356497.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507165356497.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507165457413.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507165457413.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507171607205.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507171607205.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507171727766.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507171727766.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507172050613.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507172050613.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507182746584.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507182746584.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507182824646.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507182824646.png -------------------------------------------------------------------------------- /docs/high-performance/02/assets/image-20200507182841194.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/02/assets/image-20200507182841194.png -------------------------------------------------------------------------------- /docs/high-performance/03/02.md: -------------------------------------------------------------------------------- 1 | # 对应用程序进行性能剖析 2 | 3 | 对任何需要消耗时间的任务都可以做性能剖析,也包括应用程序。实际上,剖析应用程序一般比剖析数据库服务器容易,而且回报更多。 4 | 5 | 虽然前面的演示例子都是针对 MySQL 服务器的剖析,单对系统进行性能剖析还是建议自上而下的进行,这样可以追踪自用户发起到服务器响应的整个流程。虽然性能问题大多数情况下都和数据库有关,但应用导致的性能问题也不少。性能瓶颈可能有很多影响因素: 6 | 7 | - 外部资源,比如调用了外部的 web 服务或则搜索引擎 8 | - 应用需要处理大量的数据,比如分析一个超大的 XML 文件 9 | - 在循环中执行昂贵的操作,比如滥用正则表达式 10 | - 使用了低效的算法,比如使用暴力搜索算法来查找列表中的项 11 | 12 | 幸运是,确定 MySQL 的问题没有这么复杂,只需要一款应用程序的剖析工具即可。 13 | 14 | 建议在所有的新项目中都考虑包含性能剖析的代码。 往已有的项目中加入性能剖析代码也许很困难,新项目就简单一些。 15 | 16 | 那么 **性能剖析本身会导致服务器变慢吗?** 17 | 18 | - 回答是:是因为性能剖析的确会导致应用慢一点 19 | - 回答不是:是因为性能剖析可以帮助应用运行得更快 20 | 21 | 性能剖析和定期检测都会带来 **额外的开销**。问题在于这部分的开销有多少,并且由此获得的 **收益是否能够抵消这些开销**。 22 | 23 | 大多数设计和构建过高性能应用程序的人相信,应该尽可能的测量一切可以测量的地方,并且接受这些测量带来的额外开销,这些开销应该被当成应用程序的一部分。 24 | 25 | Oracle 的性能优化大师 Tom Kyte 曾经被问到 Oracle 中的测量点的开销,他的回答是:测量点至少为性能优化贡献了 10%。大多数应用并不需要每天都运行详细的性能测量,所以实际贡献甚至超过 10%。即使不同一这个观点,应该为应用构建一些可以永久使用的轻量级的性能剖析也是有意义的。如果系统没有每天变化的性能统计,则碰到无法提前预知的性能瓶颈就是一件头疼的事情。发现问题的时候,如果有历史数据,这些历史数据价值是无限的。而且性能数据还可以帮助规划好硬件采购、资源分配、以及预测周期性的性能尖峰。 26 | 27 | 何为轻量级的性能剖析?比如可以为所有 SQL 语句计时,加上脚本总时间统计,这样做的代价不高,而且不需要在每次页面查看(page view)时都执行。如果流量趋势比较稳定,随机采样也可以,随机采样可以通过在应用程序中设置实现,来帮助定位一些严重的问题。这种策略在生产环境中尤其有用,可以发现一些其他方法无法发现的问题。 -------------------------------------------------------------------------------- /docs/high-performance/03/README.md: -------------------------------------------------------------------------------- 1 | # 服务器性能剖析 2 | 3 | 最常碰到的三个性能相关的问题是: 4 | 5 | - 如何确认服务器是否达到了性能最佳的状态? 6 | - 找出某条语句为什么执行不够快 7 | - 诊断被用户描述成「停顿」、「堆积」、「卡死」的某些间歇性疑难故障 8 | 9 | 本章将主要针对这三个问题作出解答。将提供一些工具和技巧来优化整机的性能、优化单条语句的执行速度,以及诊断或者解决那些很难观察到的问题,这些问题用户往往很难知道其根源,有时候甚至都很难察觉到它的存在 10 | 11 | 这看起来是一个间距的任务,事实证明有一个简单的方法能够从噪声中发现苗头。就是:专注于测量服务器的时间花费在哪里,使用的技术则是性能剖析(profiling)。 12 | 13 | 在本章,我们将展示如何测量系统并生成剖析报告,以及如何分析系统的整个堆栈(stack),包括从应用程序到数据库服务器到单个查询 14 | 15 | 首先要保持空杯精神,抛掉一些关于性能的常见的误区。 -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508111211415.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508111211415.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508113733111.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508113733111.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508142528230.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508142528230.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508143136237.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508143136237.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508143656065.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508143656065.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508152816361.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508152816361.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508153222923.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508153222923.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508162508331.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508162508331.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508164432061.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508164432061.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508173048217.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508173048217.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508180245780.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508180245780.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508180605954.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508180605954.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200508181144459.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200508181144459.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200509105320760.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200509105320760.png -------------------------------------------------------------------------------- /docs/high-performance/03/assets/image-20200509113138633.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/03/assets/image-20200509113138633.png -------------------------------------------------------------------------------- /docs/high-performance/04/02.md: -------------------------------------------------------------------------------- 1 | # MySQL schema 设计中的陷阱 2 | 3 | - 太多的列 4 | 5 | MySQL 的存储引擎 API 工作时需要在服务器层和存储引擎层之间通过行缓冲格式拷贝数据,然后在服务器层将缓冲内容解码成各个列。从行缓冲将编码过的列转成行数据结构的操作代价是非常高的。MyISAM 的定长行结构实际上与服务器层的行结构正好匹配,所以不需要转换。然而,MyISAM 的变长行结构和 InnoDB 的行结构总是需要转换。转换的代价依赖于列的数量。当我们研究一个 CPU 占用非常高的案例时,发现客户使用了非常宽的表(数千个字段),然而只有一小部分列会实际用到,这时转换的代价就非常高。 6 | 7 | - 太多的关联 8 | 9 | MySQL 限制了每个关联操作最多只能有 61 张表,但是 EAV(实体-属性-值)数据库需要许多自关联。实际上少于 61 张表的情况下,解析和优化查询的代价也会成为 MySQL 的问题。一个粗略的经验法则,如果希望查询执行得快速且并发性好,单个查询最好在 12 个表以内做关联。 10 | 11 | - 全能的枚举 12 | 13 | 一个枚举列要新增或则减少,都需要执行 ALTER TABLE 操作,在 5.0 版本以前 ALTER TABLE 是一种阻塞操作。在 5.1+ 如果不是在列表的末尾增加值也会一样需要 ALTER TABLE。在生产环境中,这可能会导致很长时间的阻塞 14 | 15 | - 变相的枚举 16 | 17 | 枚举(enum)列允许在列中存储一组定义值的单个值,集合(set)则允许在列中存储一组定义值中的一个或多个值。当出现下面这种情况时,应该使用枚举 18 | 19 | ```sql 20 | create table..( 21 | is_default set('Y','N') not null default 'N') 22 | -- 当一条数据不会同时出现 Y 或则 N 时。 23 | ``` 24 | 25 | - 非此发明(Not Invent Here)的 NULL 26 | 27 | 之前写了避免使用 NULL 的好处,并且建议尽可能考虑替代方案。即使需要存储一个事实上的 「空值」到表中时,也不一定非得使用 NULL,也许可以使用 0 、某个特殊值,或则空字符串作为代替 28 | 29 | 但是不要走极端 !在一些场景中,使用 NULL 可能会比某个神奇的常数更好。例如 `-1` 代表一个未知的整数,可能导致代码复杂很多,并容易引入 BUG。 30 | 31 | 下面是一个经常看到的例子 32 | 33 | ```sql 34 | create table...( 35 | dt datetime not null default '0000-00-00 00:00:00') 36 | ``` 37 | 38 | 伪造的全 0 值可能导致很多问题(可以配置 MySQL 的 SQL_MODE 来禁止不可能的日期,对于新应用这是个非常好的实践经验,它不会让创建的数据库里充满不可能的值)。值的一提的是,**MySQL 会在索引中存储 NULL 值,而 Oracle 则不会** -------------------------------------------------------------------------------- /docs/high-performance/04/03.md: -------------------------------------------------------------------------------- 1 | ## 范式和反范式 2 | 3 | 在范式化的数据库中,每个事实数据会出现并且只出现一次,相反,在反范式化的数据库中,信息是冗余的,可能会存储在多个地方。 4 | 5 | ## 范式的优点和缺点 6 | 7 | 当为性能问题而寻求帮助时,经常会被建议对 schema 进行范式化设计,尤其是写秘籍的场景。因为下面这些原因,范式化通常能够带来好处: 8 | 9 | - 范式化的更新操作通常比反范式化要快 10 | 11 | - 当数据较好的范式化时,只有很少或则没有重复数据,所以值需要修改更少的数据。 12 | 13 | - 范式化的表通常更小,可以更好的放在内存里,所以执行操作会更快 14 | 15 | - 很少有多余的数据意味着检索列表数据时更少需要 DISTINCT 或则 GROUP BY 语句。 16 | 17 | 比如部门表如果是一张单独的表,则只需要简单的查询这张表就行了。 18 | 19 | 范式化设计的 schema 的缺点是通常需要关联。稍微复杂一些的查询语句在符合范式化的 schema 上都可能需要至少一次关联,也许更多。这不但代价昂贵,也可能是一些索引测量无效。 20 | 21 | 例如,范式化可能将列存放在不同的表中,而这些列如果在一个表中本可以属于同一个索引。 22 | 23 | ## 反范式的有点和缺点 24 | 25 | 反范式化的 schema 因为所有数据都在一张表中,可以很好的避免关联。 26 | 27 | 如果 不需要关联表,则对大部分查询最差的情况则:即使没有使用索引,全表扫描。当数据比内存大时这可能比关联要快得多,因为这样避免了随机 I/O。 28 | 29 | 单独的表也能使用更有效的索引测量。就是将数据冗余在一张表中,并给他们添加索引,这会更快。 30 | 31 | ## 混用范式化和反范式化 32 | 33 | 范式化和反范式化的 schema 各有优劣,怎么选择最佳的设计? 34 | 35 | 最常见的反范式化数据的方法是复制或则缓存,在不同的表中存储相同的特定列。在 MySQL 5.+ 版本中,可以使用触发器更新缓存值。 36 | 37 | 从父表冗余到一些数据到子表的理由是排序的需要。 -------------------------------------------------------------------------------- /docs/high-performance/04/04.md: -------------------------------------------------------------------------------- 1 | # 加快 ALTER TABLE 操作的速度 2 | 3 | MySQL 的 ALTER TABLE 操作的性能对大表来说是个问题。MySQL 执行大部分修改表结构的方法是用新的结构创建一个空表,从旧表中查出所有数据插入新表,然后删除旧表。这样操作可能需要花费很长时间,如果内存不足而表又很大,而且还有很多索引的情况下更耗时间。有时候可能需要花费数小时至数天才能完成 4 | 5 | MySQL 5.+ 包含一些类型的「在线」操作的支持,这些功能不需要在整个操作过程中锁表。最近版本的 InnoDB 也支持通过排序来建索引,这使得建索引更快并且又一个紧凑的索引布局。 6 | 7 | 一般而言,大部分 ALTER TABLE 操作将导致 MySQL 服务中断。我们会战士一些在 DDL操作时有用的技巧,但这只是针对一些特殊的场景而言的。对常见的场景,能使用的技巧只有两种: 8 | 9 | - 先在一台不提供服务的机器上执行 ALTER TABLE 操作,然后和提供服务的主库进行切换 10 | - 另一种是「影子拷贝」,用要求的表结构创建一张和源表无关的新表,然后通过重命名和删表操作交换两张表。 11 | 12 | 有一些工具可以帮助完成影子拷贝的工作,如 Facebook 数据库运维团队的 「oline schema change」工具、Shlomi Noach 的 openark toolkit、Percona Tookit。 13 | 14 | 不是所有的 ALTER TABLE 操作都会引起表重建。例如,有两种方法可以改变或则删除一个列的默认值(一个方法很快,另外一种很慢)。加入要修改电影的默认租赁期限,从三天改到 5 天。下面是很慢的方式 15 | 16 | ```sql 17 | alter table sakla.film modify column rental_duration tinyint(3) not null default 5; 18 | ``` 19 | 20 | show status 显示这个语句做了 1000 次读和 1000 次插入操作。换句话说,它拷贝了整张表到一张新表,升值列的类型、大小和可是否为 null 属性都没有改变。 21 | 22 | 理论上,MySQL 可以跳过创建新表的步骤。列的默认值是上存在表的 `.frm` 文件中,所以可以直接修改这个文件而不需要改动表本身。然而 MySQL 还没有采用这种优化的方法,所有的 MODIFY COLUM 操作都将导致表重建。 23 | 24 | 另一种方式是通过 `ALTER COLUMN` 操作来改变列的默认值 25 | 26 | ```sql 27 | alter table sakila.film alter column rental_duration set default 5; 28 | ``` 29 | 30 | 该语句会直接修改 `.frm` 文件而不涉及表数据。所以该操作也非常快。 31 | 32 | ## 只修改 `.frm` 文件 33 | 34 | 从上面的例子看到直接修改 `.frm` 文件是很快的,如果愿意冒一些风险,也可以做一些其他类型的修改而不用重建表。 35 | 36 | - 移除(不是增加)一个列的 AUTO_INCREMENT 属性 37 | 38 | - 增加、移除或更改 ENUM 和 SET 常量如果移除的是已经有行数据用到其他值的常量,查询将会返回一个空子串值。 39 | 40 | 基本的技术是为想要的表结构创建一个新的 `.frm` 文件,然后用它替换掉已经存在的哪张表的 `.frm` 文件,像下面这样: 41 | 42 | 1. 创建一章有相同结构的空表,并进行所需要的修改(例如增加 ENUM 常量) 43 | 2. 执行 `FLUSH TABLE WITH READ LOCK`。 这将会关闭所有正在使用的表,并且禁止任何表被打开。 44 | 3. 交换 `.frm` 文件 45 | 4. 执行 UNLOCK TABLES 来释放第 2 步的读锁。 46 | 47 | ## 快速创建 MyISAM 索引 48 | 49 | 为了搞笑的载入数据到 MyISAM 表中,有一个常用的技巧是先禁用索引、载入数据,然后重新启用索引。 50 | 51 | ```sql 52 | alter table test.load_data disable keys; 53 | -- 加载数据 54 | alter table test.load_data enable keys; 55 | ``` 56 | 57 | 这个技巧是利用了构建索引的工作被延迟到数据完全载入以后,这个时候已经开源通过排序来构建索引了。这样做会快很多,并且使得索引树的碎片更小、更紧凑 58 | 59 | 只是该办法对唯一索引无效。因为 `disable keys` 只对非唯一索引有效。 60 | 61 | 在 InnoDB 中,有一个类似的技巧,这依赖于 InnoDB 的快速在线索引创建功能。先删除所有的非唯一索引,然后增加新的列,最后重新创建删除掉的索引。 -------------------------------------------------------------------------------- /docs/high-performance/04/README.md: -------------------------------------------------------------------------------- 1 | # Schema 与数据类型优化 2 | 3 | 良好的逻辑设计和物理设计是高性能的基石,应该根据系统将要执行的查询语句来设计 schema,这往往需要权衡各种因素。例如,反范式化的设计可以加快某些类型的查询,但同时可能使另一些类型的查询变慢。MySQL 独有的特性和实现细节对性能的影响也很大。 4 | 5 | 本章聚焦在索引优化的下一章,覆盖了 MySQL 特有的 schema 设计方面的主题。假设你已经知道如何设计数据库,不会讲解数据库设计方面的入门或则深入内容。主要关注 MySQL 数据库的设计与其他关系型数据库管理系统的区别。 6 | 7 | 本章是为接下来的两个章节做铺垫。在这三章中,我们将讨论逻辑设计、物理设计和查询执行,以及他们之间的相互作用。这既需要关注全局,也需要专注细节。还需要了解整个系统以便弄清楚各个部分如何相互影响。 8 | 9 | 在阅读完索引和查询优化章节后,建议再回过头来看看本章,也许会发现本章很有用,很多讨论的议题不能孤立的考虑。 -------------------------------------------------------------------------------- /docs/high-performance/05/02.md: -------------------------------------------------------------------------------- 1 | # 索引的优点 2 | 3 | **索引可以让服务器快速定位到表的指定位置**。但是这并不是索引的唯一作用,到目前为止可以看到,根据创建索引的数据结构不同,索引也有一些其他的附加作用。 4 | 5 | 最常见的 B-Tree 索引,按照顺序存储数据,所以 MySQL 可以用来做 order byt 和 group by 操作。因为数据是有序的,所以相关的列值都存储在一起。最后,因为索引中存储了实际的列值,所以某些查询只使用索引就能够完成全部查询。据此特性,总结有如下三个优点: 6 | 7 | 1. 索引大大减少了服务器需要扫描的数据量 8 | 2. 索引可以帮助服务器避免排序和临时表。 9 | 3. 索引可以将随机 I/O 变为顺序 I/O。 10 | 11 | 索引这个主题值得完全单独写一本书,如果想深入理解,强烈建议阅读 《Relational Database Index Design and the Optimizers》,该书详细介绍了如何计算索引的成本和作用、如何评估查询速度、如何分析索引维护的代价和其他带来的好处等。 12 | 13 | ## 三星系统 14 | 15 | 在书中介绍如何评价 **一个索引是否适合某个查询的「三星系统」**: 16 | 17 | - 索引将相关的记录放到一起,获得一星 18 | - 如果索引中的数据顺序和查找中的排列顺序一致则获得二星 19 | - 如果索引中的列包含了查询中需要的全部列则获得三星。 20 | 21 | 后续还需继续介绍这些原则。 22 | 23 | ## 索引是最好的解决方案吗? 24 | 25 | 索引并不总是最好的工具。总的来说,只有当所有帮助存储引擎快速找到记录带来的好处大于其他来带的额外工作时,索引才是最有效的。 26 | 27 | - 非常小的表:大部分情况下,简单全表扫描更高效 28 | - 中到大型表:索引就非常有效 29 | - 特大型表:建立和使用索引的代价随之增长,这种情况下,需要一种技术可以直接区分出查询需要的一组数据,而不是一条一条记录匹配。例如可以使用分区技术,请参考第 7 章 30 | 31 | 如果表的数量特别多,可以建立一个元 **数据信息**,用来查询需要用到的某些特性。 32 | 33 | 例如:执行那些需要聚合多个应用分布在多个表的数据的查询,则需要记录「哪个用户的信息存储在哪个表中」的元数据,这样在查询时就可以直接忽略那些不包含指定用户信息的表。 34 | 35 | 对于大型系统来说,这是一个常用的技巧。事实上, infobright 就是使用类似的实现,对于 TB 级的数据,定位单条记录的意义不大,所以经常会使用快级别元数据技术来替代索引。 -------------------------------------------------------------------------------- /docs/high-performance/05/06.md: -------------------------------------------------------------------------------- 1 | # 总结 2 | 3 | 通过本章来看,索引是一个非常复杂的话题。MySQL 和存储引擎访问数据的方式,加上索引的特性,使得索引称为一个影响数据访问的有力而灵活的工作(无论数据是在磁盘中还是在内存中) 4 | 5 | 在 MySQL 中,大多数情况下都会使用 B-Tree 索引。其他类型的所以大多只适合特殊目的。在合适的场景中使用索引,将大大提高查询的响应时间。 6 | 7 | 值的回顾一下这些特性以及如何使用 B-Tree 索引: 8 | 9 | 1. 单行访问是很慢的 10 | 11 | 特别是在机械硬盘存储中(SSD 的随机 I/O 要快很多,不过这任然成立)。如果服务器读取一个数据块只为了获取其中一行,那么久浪费了很多工作。最好读取的块中能包含尽可能多需要的行。**使用索引可以创建位置引用提升效率** 12 | 13 | 2. 按顺序访问范围数据是很快的。 14 | 15 | 这有两个原因: 16 | 17 | 1. 顺序 I/O 不需要多次磁盘寻道,所以比随机 I/O 要快很多(特别是针对机械硬盘) 18 | 19 | 2. 如果服务器能按顺序读取数据,那么久不再额外的排序操作,并且 group by 查询也无须再做排序和将行按组进行聚合计算了。 20 | 21 | 3. 索引覆盖查询时很快的 22 | 23 | 如果一个索引包含了查询需要的多有的列,那么存储引擎就不再需要回表查找行。这避免了大量的单行访问,而上面第 1 点已经写明单行访问是很慢的。 24 | 25 | 总的来说,编写查询语句时 **应尽可能选择合适的索引以避免单行查找**、**尽可能使用数据原生顺序从而避免额外的排序操作**,并尽可能使用索引覆盖查询。这与「三星系统」是一致的思想。 26 | 27 | 理解索引式如何工作非常重要,应该根据这些理解来创建最合适的索引,而不是根据一些诸如 *在多列索引中将选择性最高的列放在第一列* 或 *应该为 where 子句中出现的所有列创建索引* 之类的模糊的经验法则。 28 | 29 | **如何判断一个系统创建的索引式合理的呢?**一般来说,建议按照响应时间来对查询进行分析。 30 | 31 | - 找出那些 **消耗最常时间的查询** 或则那些给服务器 **带来最大压力的查询**(第三章中介绍了如何测量) 32 | - 然后检查这些查询的 schema、SQL 和索引结构 33 | - **判断是否有查询扫描了太多的行**, 34 | - 是否做了很多额外的排序或则使用了临时表, 35 | - 是否使用随机 I/O 访问数据 36 | - 是否有太多回表查询那些不在索引中的列操作 37 | 38 | 如果一个查询 **无法从所有可能的索引中获益**,则应该看看 **是否可以创建一个更合适的索引** 来提升性能。如果不行,也可以看看是否可以 **重写该查询**,将其 **转化** 成一个 **能够高效利用现有索引或则新创建索引的查询**。这也是下一章要讲解的内容。 39 | 40 | 如果根据第 3 章介绍给予响应时间的分析不能找出有问题的查询呢?是否可能我们没有注意到「很糟糕」的查询,需要一个更好的索引来获取更高的性能?一般来说,不可能。**对于诊断时住不到的查询,那就不是问题**。但是,这个查询未来有可能会成为问题,因为应用程序、数据和负载都在变化。如果仍然想找到那些索引不是很合适的查询,并在他们成为问题前进行优化,则可以使用 pt-query-digest 的查询审查「review」功能,分析其 explain 出来的执行计划。 41 | 42 | -------------------------------------------------------------------------------- /docs/high-performance/05/README.md: -------------------------------------------------------------------------------- 1 | # 创建高性能索引 2 | 3 | 索引是存储引擎用于快速找到记录的一种 **数据结构**。这是索引的基本功能,除此之外,本章还讨论索引其他一些方面有用的属性。 4 | 5 | 索引对于表数据量大时,效果明显且很重要,这也包括不恰当的索引带来的性能影响。 6 | 7 | 由于索引经常被忽略,有时候甚至被误解,实际案例中经常会遇到由糟糕索引导致的问题。这也是本书把索引放到了查询前面讲解的原因。 8 | 9 | **索引优化应该是对查询性能优化最有效的手段了**。能够轻易将查询性能提高几个数量级,「最优」索引有时比一个「好的」索引性能要好两个数量级。创建一个真正「最优」的索引经常需要重写查询,所以本章和下一章的关系非常紧密 -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200521140623920.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200521140623920.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200521142110423.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200521142110423.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524153542584.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524153542584.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524153642254.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524153642254.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524153901884.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524153901884.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524155447997.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524155447997.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524162356587.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524162356587.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524162651959.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524162651959.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524162916306.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524162916306.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524163055674.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524163055674.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524164205504.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524164205504.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524164328663.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524164328663.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524185023871.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524185023871.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524185214938.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524185214938.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524185421351.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524185421351.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524185822696.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524185822696.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524193126939.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524193126939.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524193651841.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524193651841.png -------------------------------------------------------------------------------- /docs/high-performance/05/assets/image-20200524223336352.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/05/assets/image-20200524223336352.png -------------------------------------------------------------------------------- /docs/high-performance/06/01.md: -------------------------------------------------------------------------------- 1 | # 为什么查询速度会慢 2 | 3 | 在尝试编写快速的查询之前,需要清楚一点,真正重要是 **响应时间**。如果把 **查询** 看成是 **一个任务**,那么 **它由一系列子任务组成**,每个子任务都会消耗一定的时间。如果要优化查询,实际上要优化其子任务: 4 | 5 | - 要么消除其中一些子任务 6 | 7 | - 要么减少子任务的执行次数 8 | 9 | - 要么让子任务运行得更快 10 | 11 | 有时候可能还需要修改一些查询,减少这些查询对系统中运行的其他查询的影响。这种情况下,你是在减少一个查询的资源消耗。 12 | 13 | MySQL 在执行查询的时候有哪些子任务,哪些子任务运行的速度很慢?这很难给出完整的列表,如果按照第 3 章介绍的方法对查询进行剖析,就能看到查询所执行的子任务。通常来说,**查询的生命周期** 大致可以按照顺序来看: 14 | 15 | - 从客户端 16 | - 到服务器 17 | - 在服务器上进行解析 18 | - 生成执行计划 19 | - 执行 20 | - 并返回结果给客户端 21 | 22 | 其中 **执行** 可以认为是整个生命周期中最重要的阶段,这其中包括了大量为检索数据到存储引擎的调用以及调用后的数据处理,包括排序、分组等。 23 | 24 | 在完成这些任务的时候,查询需要在不同的地方花费时间,包括: 25 | 26 | - 网络 27 | - CPU 计算 28 | - 生成统计信息和执行计划 29 | - 锁等待(互斥等待) 30 | 31 | 等等的操作,尤其是向抵触存储引擎检索数据的调用操作,这些调用需要在内存操作、CPU 操作和内存不足时导致的 I/O 操作上消耗时间。根据存储引擎不同,可能还会产生大量的上下文切换以及系统调用。 32 | 33 | 在 **每一个消耗大量时间的查询** 案例中,我们都能看到一些 **不必要的额外操作**、某些操作被额外的 **重复了很多次**、**某些操作执行得太慢** 等。优化查询的目的就是 **减少和消除** 这些 **操作所花费的时间**。 34 | 35 | 再次申明一点,对于一个查询的全部生命周期,上面列得不完整。这里只是想说明:了解查询的生命周期、清楚查询的时间消耗情况对于优化查询有很大的意义。 36 | 37 | ### 38 | 39 | -------------------------------------------------------------------------------- /docs/high-performance/06/03.md: -------------------------------------------------------------------------------- 1 | # 重构查询的方式 2 | 3 | 在优化有问题的查询时,目标应该找到一个更优的方法获得实际需要的结果,而不是一定总是需要从 MySQL 获取一模一样的结果集。 4 | 5 | 有时候,可以将查询转换一种写法让其返回一样的结果,但是性能更好。 6 | 7 | 也可以通过修改应用代码,用另一种方式完成查询,最终达到一样的目的。 8 | 9 | 本节将介绍如何通过这种方式来重构查询,并展示何时需要使用这样的技巧。 10 | 11 | ## 一个复杂查询还是多个简单查询 12 | 13 | 设计查询的时候一个需要考虑的重要问题是:**是否需要将一个复杂的查询分成多个简单的查询**。 14 | 15 | 在传统的实现中,总是强调需要数据库层完成尽可能多的工作,这样做的逻辑在于以前总认为网络通信、查询解析和优化是一件代价很高的事情。 16 | 17 | 这种想法对于 MySQL 并不适用,从设计上让链接和断开连接都很轻量级,在返回一个小的查询结果方面很高效。现代的网络速度比以前快很多,无论是带宽还是延迟。在某些版本的 MySQL 上,即使一个通用服务器上,也 **能够运行每秒超过 10 万的查询**,即使是一个千兆网卡也能轻松满足每秒超过 2000 次的查询。所以 **运行多个小查询已经不是大问题了** 18 | 19 | MySQL 内部每秒能够扫描内存中上百万行数据,相比之下,MySQL 响应数据给客户端就慢得多了。在 **其他条件都相同的时候,使用尽可能少的查询当然是更好** 的。但是有时候将一个大查询分解为多个小查询是很有必要的。 20 | 21 | 不过,在应用设计的时候,如果一个查询能够胜任时还写多个独立查询是不明智的。例如:对一个数据表做 10 次独立的查询来返回 10 行数据,每个查询返回一条结果,查询 10 次。 22 | 23 | ## 切分查询 24 | 25 | 有时候对于 **一个大查询我们需要「分而治之」**,将大查询切分成小查询,每个查询功能完全一样,只完成一小部分,每次只返回一小部分查询结果。这不就是分页查询的思想吗? 26 | 27 | 删除旧的数据就是一个好的例子。定期删除大量数据时,如果用一个大的语句一次性完成的话,则 28 | 29 | - 可能需要一次锁住很多数据 30 | - 占满整个事务日志 31 | - 耗尽资源 32 | - 阻塞很多小的但重要的查询。 33 | 34 | 将一个大的 delete 语句切分成多个较小的查询可以: 35 | 36 | - 尽可能小的影响 MySQL 性能 37 | - 还可以减少 MySQL 复制的延迟 38 | 39 | 例如,需要每个月运行一次下面的查询: 40 | 41 | ```sql 42 | delete from messages where created < date_sub(now(), interval 3 month) 43 | ``` 44 | 45 | 可以用类似下面的办法来完成同样的工作 46 | 47 | ```sql 48 | rows_affected = 0 49 | do { 50 | rows_affected = do_query( 51 | "delete from messages where created < date_sub(now(), interval 3 month)" 52 | ) 53 | } while rows_affected > 0 54 | ``` 55 | 56 | 一次性删除一万行数据一般来说是一个比较高效而且对服务器影响也最小的做法(如果是事务性引擎,很多时候小事务能更高效)。同时,需要注意的是,**如果每次删除数据后,都暂停一会再做下一次删除**,这样也可以将服务器上原本一次性的压力分散到一个很长的时间段中,就可以大大降低对服务器的影响,还可以大大减少删除时所的持有时间。 57 | 58 | ## 分解关联查询 59 | 60 | **很多高性能的应用都会对关联查询进行分解**。简单说:对单表查询,在应用程序中进行关联。 61 | 62 | 例如下面这个查询: 63 | 64 | ```sql 65 | select * from tag 66 | join tag_post on tag_post.tag_id = tag.id 67 | join post on tag_post.post_id = post.id 68 | where tag.tag = 'mysql'; 69 | ``` 70 | 71 | 可以分解成下面的这些查询来代替 72 | 73 | ```sql 74 | select * from tag_where tag = 'mysql' 75 | select * from tag_post where tag_id = 1234; 76 | select * from post where post.id in(123,456,9098); 77 | ``` 78 | 79 | 乍一看,这样做并没有什么好处,原本一条查询,这里却变成多条查询,返回的结果又是一样的。事实上,用分解关联查询的方式重构查询有如下的优势: 80 | 81 | - 让缓存的效率更高 82 | 83 | 许多应用程序可以方便的缓存单标查询对应的结果对象。 84 | 85 | 例如:上面查询中 tag 已经被缓存了,那么应用就可以跳过第一个查询。 86 | 87 | 再如:应用中已经缓存了 ID 为 123,456 的内容,那么低三个查询的 `in()` 中就可以少几个 ID. 88 | 89 | 另外对 MySQL 的查询缓存来说,如果关联中的某个表发生了变化,那么久无法使用查询缓存了,而拆分之后,如果某个表现很少改变,那么急于该表的查询就可以重复利用资源缓存结果了。 90 | 91 | - 将查询分解后,执行单个查询可以减少锁的竞争 92 | 93 | - 在应用层做关联,可以容易对数据库进行拆分,更容易做到高性能和扩展。 94 | 95 | - 查询本身效率也会有所提升,这个可比随机的关联要更好高效 96 | 97 | - 可以减少冗余记录的查询 98 | 99 | 在应用层做关联查询,意味着对于某条记录应用,从这里看,这样的重构还可能会减少网络和内存的消耗。 100 | 101 | - 更近一步,这样做相当于在应用中实现了 **哈希关联**,而不是使用 MySQl 的嵌套循环关联。某些场景的哈希关联效率要高很多。 102 | 103 | 在很多场景下,**通过重构查询将关联放到应用程序中将会更加高效**,这样的场景有很多。比如: 104 | 105 | - 当应用能够方便的缓存单个查询的结果的时候 106 | - 当可以将数据分布到不同的 MySQL 服务器上的时候 107 | - 当能使用 `in()` 方式替代关联查询的时候 108 | - 当查询中使用同一个数据表的时候 109 | 110 | -------------------------------------------------------------------------------- /docs/high-performance/06/06.md: -------------------------------------------------------------------------------- 1 | # MySQL 查询优化器的提示 2 | 本章内容概念思路太多了,很容易看不下去,硬看的话,感觉只是抄书了,一点都没有记住什么。先不看这本书了 -------------------------------------------------------------------------------- /docs/high-performance/06/07.md: -------------------------------------------------------------------------------- 1 | # 优化特定类型的查询 -------------------------------------------------------------------------------- /docs/high-performance/06/08.md: -------------------------------------------------------------------------------- 1 | # 案例学习 -------------------------------------------------------------------------------- /docs/high-performance/06/09.md: -------------------------------------------------------------------------------- 1 | # 总结 -------------------------------------------------------------------------------- /docs/high-performance/06/README.md: -------------------------------------------------------------------------------- 1 | # 查询性能优化 2 | 3 | 前面讲解了如何设计 **最优的库表结构**、如何 **建立最好的索引**,还需要 **合理的设计查询**。如果查询写得很糟糕,即使库表结构再合理、索引再合适,也无法实现高性能。 4 | 5 | 在获得编写 MySQL 查询的经验的同时,也将学习到 **如何为高效的查询设计表和索引**。同样的,也可以学习到在 **优化库表结构时会影响到那些类型的查询**。这个过程需要时间,建议在学习后面章节时多回头看看这三章的内容。 6 | 7 | 本章将从查询设计的一些基本原则开始,这也是在发现查询效率不高的时候 **首先需要考虑的因素**。然后介绍一些更深的查询优化技巧,并会介绍一些 MySQL 优化器内部的机制。 8 | 9 | 我们将展示 MySQL 是如何执行查询的,你也将学会如何去改变一个查询的执行计划。最后,我们要看一下 MySQL 优化器在哪些方面做得还不够,并探索优化的模式,以帮助 MySQL 更有效的执行查询。 10 | 11 | -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200528212208619.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200528212208619.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200529213542757.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200529213542757.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200529214536307.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200529214536307.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200529214753762.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200529214753762.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200530122358064.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200530122358064.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200530125716379.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200530125716379.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200530132505039.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200530132505039.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200530184951471.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200530184951471.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200530185158299.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200530185158299.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200530190512864.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200530190512864.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200530190514348.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200530190514348.png -------------------------------------------------------------------------------- /docs/high-performance/06/assets/image-20200530190634003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/high-performance/06/assets/image-20200530190634003.png -------------------------------------------------------------------------------- /docs/high-performance/README.md: -------------------------------------------------------------------------------- 1 | # 高性能 MySQL(第三版) 2 | 3 | ::: tip 4 | 5 | 本书概念和理论较多,实际操较少,所以基本上会全部记录书上的信息。 6 | 7 | 特别是在在一些较多内容,并且无法很好理解的情况下,基本上是书上的原文抄写。 8 | ::: -------------------------------------------------------------------------------- /docs/high-performance/index.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | return [ 3 | '', 4 | { 5 | title: '01. MySQL 架构与历史', 6 | children: [ 7 | '01/', 8 | '01/01.md', 9 | '01/02.md', 10 | '01/03.md', 11 | '01/04.md', 12 | '01/05.md', 13 | '01/06.md', 14 | '01/07.md', 15 | '01/08.md' 16 | ] 17 | }, 18 | { 19 | title: '02. MySQL 基准测试', 20 | children: [ 21 | '02/', 22 | '02/01.md', 23 | '02/02.md', 24 | '02/03.md', 25 | '02/04.md', 26 | '02/05.md' 27 | ] 28 | }, 29 | { 30 | title: '03. 服务器性能剖析', 31 | children: [ 32 | '03/', 33 | '03/01.md', 34 | '03/02.md', 35 | '03/03.md', 36 | '03/04.md' 37 | ] 38 | }, 39 | { 40 | title: '04. Schema 与数据类型优化', 41 | children: [ 42 | '04/', 43 | '04/01.md', 44 | '04/02.md', 45 | '04/03.md', 46 | '04/04.md' 47 | ] 48 | }, 49 | { 50 | title: '05. 创建高性能索引', 51 | children: [ 52 | '05/', 53 | '05/01.md', 54 | '05/02.md', 55 | '05/03.md', 56 | '05/04.md', 57 | '05/05.md', 58 | '05/06.md' 59 | ] 60 | }, 61 | { 62 | title: '06. 查询性能优化', 63 | children: [ 64 | '06/', 65 | '06/01.md', 66 | '06/02.md', 67 | '06/03.md', 68 | '06/04.md', 69 | '06/05.md', 70 | '06/06.md', 71 | '06/07.md', 72 | '06/08.md', 73 | '06/09.md' 74 | ] 75 | } 76 | ] 77 | } 78 | -------------------------------------------------------------------------------- /docs/imooc-mysql8/01.md: -------------------------------------------------------------------------------- 1 | # 课程序言 2 | 3 | ## 课程收获 4 | 5 | 为什么设计本课程? 6 | 7 | - SQL 基础知识相对匮乏 8 | - 期望更加系统全面的学习 9 | 10 | 课程收获 11 | 12 | - 用 SQL 解决企业中存在的真实业务痛点问题 13 | - 用 SQL 优化彰显你的个人价值 14 | 15 | ## 课程适合人群 16 | 17 | - 开发工程师 18 | - 产品、运营、市场 19 | - 测试工程师 20 | - 运维工程师 21 | 22 | ## 课程内容 23 | 24 | 1. 数据库选型 25 | 26 | - 选型之初:NoSQL VS SQL 27 | - 选型确认:各种数据存储系统的适应场景 28 | - 选型之终:构建 MySQL 开发环境 29 | 30 | 2. 数据库建模 31 | 32 | - 业务分析(人和):一切故事的开始 33 | - 逻辑设计(天时):范式化 VS 反范式化 34 | - 物理设计(地利):根据 MySQL 特点进行设计 35 | 36 | 3. 数据库访问 37 | 38 | 根据场景的不同和人群的不同,选择的的工具不同 39 | 40 | - 初级武器:MySQL 客户端 41 | - 神兵利器:常用 GUI 工具 42 | - 高阶神器:MySQL 驱动 43 | - 必杀秘籍:访问故障处理 44 | 45 | 4. SQL 开发(本课精髓) 46 | 47 | - 基本功:DCL、DDL、DML 48 | - 必备技:常用函数 49 | - 高阶功法:CTE 以及 窗口函数 50 | 51 | 5. SQL 优化(本课灵魂) 52 | 53 | - 优化前提:分析执行计划 54 | - 优化进阶:索引和 SQL 改写 55 | - 专家技能:排查性能瓶颈 56 | 57 | 6. 事物和高并发 58 | 59 | - 问到:什么是事物 60 | - 发现:高并发的隐患 61 | - 知否:事物隔离级别 62 | - 顿悟:阻塞和死锁 63 | 64 | ## 课程环境 65 | 66 | - CentOS 7 67 | - MySQL 8.0 68 | - SQLyog:GUI 工具 69 | 70 | ## 课程学习的路线 71 | 72 | 该讲师录制了好几个 MySQL 相关的视频,学习顺序如下: 73 | 74 | 1. 给程序员的 MySQL 必知必会 75 | 76 | 侧重数据库设计和 SQL 开发 77 | 78 | 2. MySQL 全面提升,打造抗得住的 MySQL 架构 79 | 80 | 侧重 MySQL 高可用架构设计 81 | 82 | 3. MYSQL + MyCAT 搭建高可用企业级集群 83 | 84 | 侧重 MySQL 高可用架构设计 85 | 86 | 4. MySQL 电商项目 87 | 88 | 侧重综合应用 89 | 90 | 5. MySQL 面试指南 91 | 92 | 侧重综合应用 93 | 94 | -------------------------------------------------------------------------------- /docs/imooc-mysql8/02/assets/image-20200413230903756.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/02/assets/image-20200413230903756.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/02/assets/image-20200414221316390.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/02/assets/image-20200414221316390.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/03/assets/image-20200418213303353.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/03/assets/image-20200418213303353.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/03/assets/image-20200418214759776.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/03/assets/image-20200418214759776.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/03/assets/image-20200418215328833.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/03/assets/image-20200418215328833.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/03/assets/image-20200418215602115.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/03/assets/image-20200418215602115.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/03/assets/image-20200418215912801.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/03/assets/image-20200418215912801.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/03/assets/image-20200418220110463.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/03/assets/image-20200418220110463.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/03/assets/image-20200418220250952.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/03/assets/image-20200418220250952.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/03/assets/image-20200419135115513.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/03/assets/image-20200419135115513.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/04/README.md: -------------------------------------------------------------------------------- 1 | # 如何访问 MySQL 2 | 3 | 常用客户端: 4 | 5 | - 命令行工具:mysql 6 | 7 | 随 Mysql 服务器安装而安装的工具 8 | 9 | - 图形化管理工具:SQLyog、Navicat 10 | 11 | - MySQL 连接器:Connector/ODBC、Connector/J 12 | 13 | 官方支持的驱动程序 14 | 15 | ## 命令行工具 mysql 16 | 17 | ```sql 18 | mysql -uroot -p -hlocalhost 19 | 20 | 选项与参数: 21 | -u:用户 22 | -p:使用交互密码 23 | -h:链接指定的 mysql 服务器 24 | ``` 25 | 26 | ## Python 访问 mysql 27 | 28 | ```bash 29 | yum install python-setuptools python-deve 30 | # 使用 python 安装 pip 工具 31 | curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py 32 | python get-pip.py 33 | pip install --upgrade setuptools 34 | pip install PyMySQL 35 | 36 | # 进入 python 交互界面 37 | & python 38 | >>> help 39 | help > module 40 | # 在输出信息中找到 pymysql 模块 41 | help > prompt 42 | # 导入一下,如果不报错,就表示没有问题 43 | >>> import pymysql 44 | ``` 45 | 46 | 本章不再继续,笔者暂时不会使用 python 47 | 48 | -------------------------------------------------------------------------------- /docs/imooc-mysql8/05/README.md: -------------------------------------------------------------------------------- 1 | # 日常工作 DCL、DDL 2 | 3 | 本章品味独特,剑指 Geek Style。围绕核心是“工作”,针对日常工作常用的知识。包含工作基本功+工作必备技, 4 | 两大部分: 【工作基本功】DCL& DDL; 【工作必备技 】常用函数。 5 | 6 | ## 初识 SQL 7 | 8 | - 什么是 SQL:一种描述性语言 9 | - SQL 语言的作用:对存储在 RDBMS 中的数据进行增删改查等操作 10 | - 常用的 SQL 语言的种类:DCL、DDL、DML、TCL 11 | - DCL:[数据库管理语句](./01.md) 12 | - DDL:数据定义类语句 13 | - DML:数据操作语句 14 | - TCL:事物控制类语句 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/imooc-mysql8/06/04.md: -------------------------------------------------------------------------------- 1 | # 总结 2 | 3 | ## 在 SQL 开发中容易犯的错误 4 | 5 | - 使用 `count(*)` 判断是否存在符合条件的数据 6 | 7 | 可以使用 `SELECT ... LIMIT 1` 来,因为有优化 8 | 9 | 注意:笔者这里没有 get 到点,到底说的是怎么判断? 10 | 11 | - 在执行一个更新语句后,使用查询方式判断此更新语句是否有执行成功 12 | 13 | 可以使用 `ROW_COUNT()` 函数判断修改的行数 14 | 15 | - 试图在 ON 条件中过滤不满足条件的记录 16 | 17 | ```sql 18 | -- 查询出分类 iD = 5 的课程名称和分类名称 19 | select ic.class_id, i.title, ic.class_id 20 | from imc_class ic 21 | left join -- 这里使用了左外连接 22 | imc_course i on ic.class_id = i.class_id 23 | and i.class_id = 5 -- 并在 ON 后面使用了 and 过滤 24 | -- 这里其实是一个坑,左外连接,左边全都出来,这里判定了一个右表的数据,所以就不满足我们的要求了 25 | ``` 26 | 27 | | class\_id | title | class\_id | 28 | | :--- | :--- | :--- | 29 | | 5 | MySQL课程-04097 | 5 | 30 | | 5 | MySQL课程-84741 | 5 | 31 | | 5 | SQLServer课程-84646 | 5 | 32 | | 5 | SQLServer课程-73954 | 5 | 33 | | 5 | MySQL课程-56069 | 5 | 34 | | 5 | PostgreSQL课程-49682 | 5 | 35 | | 5 | MySQL课程-53657 | 5 | 36 | | 1 | NULL | 1 | 37 | | 2 | NULL | 2 | 38 | | 3 | NULL | 3 | 39 | 40 | 可以看到,不为 5 的也会出现,但是只有为 5 的 title 有数据,其他的没有是因为生效的是右边的过滤数据。右边都过滤掉了,这行数关联的部分就不会显示出来了 41 | 42 | **避免这种误操作的情况:**在 where 中过滤 43 | 44 | - 在使用 IN 进行子查询的判断时,在列中未指定正确的表名 45 | 46 | 如:`select A1 from A where A1 in (select A1 from B)`,这时尽管 B 中并不存在 A1 列的数据,也不会报错,而是会列出 A 表中的所有数据。 47 | 48 | ```sql 49 | -- 查询课程名称在 imc_user 中存在的 title;我们知道 在 imc_user 中根本就没有 title 50 | select * from imc_course where title in (select title from imc_user) 51 | ``` 52 | 53 | 这个错误不太好查找,因为不会报错。 54 | 55 | 避免:使用表名来限定列名称,如 `imc_user.title` 这就会报错了,该表中的确没有这个列 56 | 57 | - 对于表中定义的具有 not null 和 default 值的列,在插入数据时直接插入 NULL 值 58 | 59 | ## 知识点回顾 60 | 61 | - 如何使用 DCL 语句来管理数据库的访问 62 | - 如何使用 DDL 语句来建立数据库对象 63 | - 如何使用 DML 语句来操作数据库中的数据 64 | - MySQL 常用的系统函数 65 | - MySQL 8.0 新增的通用表达式和窗口函数 66 | - 通用表达式:代替子查询 67 | - 窗口函数:适合用在统计分析类的场景,提高效率 68 | - 在 SQL 开发中容易犯的错误 69 | 70 | -------------------------------------------------------------------------------- /docs/imooc-mysql8/06/README.md: -------------------------------------------------------------------------------- 1 | # 高阶技能:DML & 常用函数 2 | 本章带你玩转SQL开发,学习其实可以很快乐哦。围绕核心是“工作”较为高阶技能和加薪技能,主要是如下两部分: 3 | 4 | - 【工作高阶技】DML 语句; 5 | - 【工作加薪技】系统常用函数、窗口函数。 -------------------------------------------------------------------------------- /docs/imooc-mysql8/09/assets/image-20200513224346202.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zq99299/mysql-tutorial/a3ea989083881c5f4208198a21c7910e05846faa/docs/imooc-mysql8/09/assets/image-20200513224346202.png -------------------------------------------------------------------------------- /docs/imooc-mysql8/README.md: -------------------------------------------------------------------------------- 1 | # 给程序员的 MySQL 8.0 必知必会 2 | 3 | - [课程序言](./01.md) 4 | - [技术选型之数据库选型](./02/) 5 | - [数据库设计](./03/) 6 | - [如何访问 MySQL](./04/) 7 | - [日常工作 DCL、DDL](./05/) 8 | 9 | - [访问控制语句 DCL](./05/01.md) 10 | - [创建数据库对象 DDL](./05/02.md) 11 | - [高阶技能:DML & 常用函数](./06/) 12 | 13 | - [DML 语句](./06/01.md) 14 | - [系统常用函数](./06/02.md) 15 | - [SQL 高级特性](./06/03.md) 16 | - [总结](./06/04.md) 17 | - [SQL 优化](./07/) 18 | - [SQL 的索引优化](./08/) 19 | - [事务与并发控制](./09/) 20 | -------------------------------------------------------------------------------- /docs/imooc-mysql8/index.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | return [ 3 | '', 4 | '01.md', 5 | '02/', 6 | '03/', 7 | '04/', 8 | { 9 | title: '日常工作 DCL、DDL', 10 | children: [ 11 | '05/', 12 | '05/01.md', 13 | '05/02.md' 14 | ] 15 | }, 16 | { 17 | title: '高阶技能:DML & 常用函数', 18 | children: [ 19 | '06/', 20 | '06/01.md', 21 | '06/02.md', 22 | '06/03.md', 23 | '06/04.md' 24 | ] 25 | }, 26 | { 27 | title: 'SQL 优化', 28 | children: [ 29 | '07/' 30 | ] 31 | }, 32 | { 33 | title: 'SQL 的索引优化', 34 | children: [ 35 | '08/' 36 | ] 37 | }, 38 | { 39 | title: '事务与并发控制', 40 | children: [ 41 | '09/' 42 | ] 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mysql-tutorial", 3 | "version": "0.0.1", 4 | "description": "使用 vuepress 生成的 markdown 文档站点", 5 | "author": "mrcode <99299684@qq.com>", 6 | "private": false, 7 | "scripts": { 8 | "docs:dev": "vuepress dev docs --open", 9 | "docs:devx": "node --max_old_space_size=4096 ./node_modules/vuepress/cli.js dev docs --open", 10 | "docs:build": "vuepress build docs", 11 | "docs:buildx": "node --max_old_space_size=4096 ./node_modules/vuepress/cli.js build docs" 12 | }, 13 | "dependencies": { 14 | "@vssue/api-github-v3": "^1.4.0", 15 | "moment": "^2.24.0", 16 | "vuepress-plugin-baidu-autopush": "^1.0.1", 17 | "vuepress-plugin-baidu-tongji-analytics": "^1.0.0", 18 | "vuepress-plugin-code-copy": "^1.0.4" 19 | }, 20 | "devDependencies": { 21 | "@vuepress/plugin-back-to-top": "^1.4.1", 22 | "@vuepress/plugin-medium-zoom": "^1.4.1", 23 | "@vuepress/plugin-pwa": "^1.4.1", 24 | "vuepress": "^1.4.1" 25 | } 26 | } 27 | --------------------------------------------------------------------------------