summaryrefslogtreecommitdiff
path: root/MySQL使用过程问题小结-1.md
blob: 5f297142f87bc745d0329f40b6013a6f8f12b36f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
## MySQL 使用过程问题小结
### 数据库设计&使用规范
#### 数据库&表&字段命名规范
[参考摘抄](https://www.cnblogs.com/slgkaifa/p/7245519.html)

1. 表名一般以 __模块名称_详细表名__ 来实现,同一个模块的前缀是一样的
2. 表名称不应该取得太长( __一般不超过三个英文单词__ ,不推荐使用中文拼音,总长度不要超过30个字符)
3. 一些作为 __多对多连接表__ ,能够 __使用两个表的前缀作为表名__ :如:用户登录表User_Login。用户分组表User_GroupInfo,这两个表建立多对多关系的表名为:User_Group_Relation(关系统一用Relation)
4. 注意一点, __主键在做其它表的外键时__ ,或者在被其它表引用时, __字段说明和字段名尽量保持一致__ 。比方发帖表BBS_Topic里的用户字段写成UI_ID,这样跟用户信息表User_Info的主键UI_ID保持一致,看起来舒服,相应关系非常明白,也不容易错,前后不一致时easy令人费解。
5. 当系统中有一些少量的、反复出现的值时, __使用字典表来节约存储空间和优化查询__ 。如地区、系统中用户类型的代号等。这类值不会在程序的执行期变化,可是须要存储在数据库中。 __一般数据库中都有一个数据字典表__ ,用来保存系统所用到的基础数据,大型的字段表如省份城市区域的字典表, __统一以Dictionary_作为前缀__ 。建一个基础数据字典表的作用非常重要,其它的比方地区表(Sys_DicArea),汉语拼音表(Sys_DicCharacter)(用来汉字和拼音的转换)由于数据量较大,单独建表。
6. 与字段有关, __默认的一些特殊字段__ 。比方一些业务处理表中,除了加入生成的自己主动编号ID(一般作为主键用),该记录创建的时间CreateDate(创建时间)、该记录的创建人CreatBy(注意这里没UI_ID(用户信息表User_Info的主键UI_ID),由于还有改动人),最后改动人LastEditBy。最后改动时间LastEditDate。(这些能够直接使用中文字符,而不使用编码,提高查询的效率)同一时候有的时候须要注意, __删除的时候并不真的删除该记录__ ,而是 __加入一个标识位__ ,比方XX_DeleteStaus删除状态。1是有效的,0则是无效的。
7. __命名表时,用单数形式表示名称__ 。比如。使用 Employee,而不是 Employees。
8. 数据库中应建立这样一个表,就是 __数据库本身的字段信息__ 。表的说明,也就是数据库设计文档的一个表。方便查询使用,有什么不明的能够直接从数据库查询,数据库文档丢失,凝视丢失,都能够又一次起作用。
9. __每一个表都应该有一个主键,这个主键最好是数字,并且是递增的__ 。有非常多表的主键用32位字符编码,这样做的目的很多其它的是从安全考虑的。由于字符多时索引时效率低,而使用自增列也不是非常少,比方加入主表和从表操作时。主表的主键是从表的外键,这个时候还有取返回值,然后再加入,不能够同一时候加入。主键能够用自己定义的规则,大部分用MAX(ID)的做法,也能够自己定义一个序列表,有点像序列。或者用时间的年月日秒详细到毫秒。关于列的命名,建议对数据类型也做一些规范,由于非常easy确定。仅仅有四种主要类型:数字,字符,时间,逻辑值,这些在类型上和长度上都能够定好规范,统一起来。
10. __操作日志表,登录日志表,这是数据库中必备的两个表__ 。这个记录也须要做进一步的保存。这个有两种情形,一是详细到单个字段的操作日志。二是整个表的操作日志。
常见的几个表详细说明:操作日志表Sys_OperateLog、登录日志表Sys_LoginLog、系统字典表Sys_Dictionary、系统字典表类型Sys_DicType

[参考摘抄](https://www.cnblogs.com/pangguoming/p/7126512.html)

1. 数据库命名规范:采用 __26个英文字母__ (区分大小写)和0-9的自然数(经常不需要)加上 __下划线\___ 组成,命名简洁明确,多个单词用下划线_分隔,一个项目一个数据库,多个项目慎用同一个数据库
2. 数据表命名规范:__全部小写命名,禁止出现大写__; __禁止使用数据库关键字__ ,如:name,time ,datetime,password等;表的名称一般 __使用名词或者动宾短语__ ;明细表的名称为:主表的名称+字符dtl(detail缩写);表必须 __填写描述信息__ (使用SQL语句建表时)。命名规范:①模块_+功能点  示例:alllive_log   alllive_category;②功能点  示例:live   message;③通用表  示例:all_user。统一命名规则, __动宾短语分离且动宾逻辑顺序统一__ 。
3. 数据库字段命名规范:在命名表的列时, __不要重复表的名称__ ;不要在列的名称中包含数据类型;字段命名 __使用完整名称__ ,禁止缩写
4. 所有字段在设计时,除以下数据类型timestamp、image、datetime、smalldatetime、uniqueidentifier、binary、sql_variant、binary 、varbinary外, __必须有默认值__ , __字符型的默认值为一个空字符值串'',数值型的默认值为数值0,逻辑型的默认值为数值0__ ,系统中所有逻辑型中数值0表示为“假”,数值1表示为“真”,datetime、smalldatetime类型的字段没有默认值,必须为NULL
5. 用尽量少的存储空间来存储一个字段的数据:使用int就不要使用varchar、char;用varchar(16)就不要使varchar(256);IP地址使用int类型;固定长度的类型最好使用char,例如:邮编(postcode);能使用tinyint就不要使用smallint,int;最好给每个字段一个默认值,最好不能为null;字符转化为数字(能转化的最好转化,同样节约空间、提高查询性能);避免使用NULL字段(NULL字段很难查询优化、NULL字段的索引需要额外空间、NULL字段的复合索引无效);少用text类型(尽量使用varchar代替text字段)
6. 数据库中每个字段的规范描述:(1)尽量遵守第三范式的标准(3NF),表内的每一个值只能被表达一次,表内的每一行都应当被唯一的标识,表内不应该存储依赖于其他键的非键信息;(2)如果字段事实上是与其它表的关键字相关联而未设计为外键引用,需建索引;(3)如果字段与其它表的字段相关联,需建索引;(4)如果字段需做模糊查询之外的条件查询,需建索引;(5)除了主关键字允许建立簇索引外,其它字段所建索引必须为非簇索引;

#### SQL语言编码规范
1. 所有关键字必须大写,如:INSERT、UPDATE、DELETE、SELECT及其子句,IF……ELSE、CASE、DECLARE等
2. 所有函数及其参数中除用户变量以外的部分必须大写
3. 在定义变量时用到的数据类型必须小写

#### 注释编写规范
注释可以包含在批处理中,在触发器、存储过程中包含描述性注释将大大增加文本的可读性和可维护性,本规范建议: 

1. 注释以英文为主,实际应用中,发现以中文注释的SQL语句版本在英文环境中不可用,为避免后续版本执行过程中发生某些异常错误,建议使用英文注释
2. 注释尽可能详细、全面创建每一数据对象前,应具体描述该对象的功能和用途,传入参数的含义应该有所说明,如果取值范围确定,也应该一并说明,取值有特定含义的变量(如boolean类型变量),应给出每个值的含义
3. 注释语法:单行注释、多行注释;单行注释:注释前有两个连字符(--)对变量、条件子句可以采用该类注释;多行注释:符号之间的内容为注释内容,对某项完整的操作建议使用该类注释
4. 注释简洁,同时应描述清晰
5. 函数注释: 编写函数文本--如触发器、存储过程以及其他数据对象--时,必须为每个函数增加适当注释,该注释以多行注释为主

### 数据库安装&登录&退出
1. 数据库安装包下载及安装:

        ```bash
        rpm -i mysql-community-release-el7-5.noarch.rpm
        yum install mysql-community-server
        ```

2. mysql 服务启动停止查看:

        ```bash
        systemctl start mysql # 启动 mysql 
        systemctl stop mysql # 停止 mysql
        systemctl status mysql # 查看 mysql 状态
        ```

3. 安装后初始配置(建立数据库登录用户及密码):`mysqladmin -u root password`

        ```bash
        mysqladmin -u root password # 新建用户名及密码
        chkconfig --level 2345 mysqld on # 设置 mysql 服务的运行级信息
        systemctl start mysql # 重启 mysql 服务

        [root@iz2ze8e1dj06n0wjqj19n2z ~]# systemctl start mysql
        [root@iz2ze8e1dj06n0wjqj19n2z ~]# mysqladmin -u root password
        New password: 【此处输入密码】
        Confirm new password: 【此处重复输入密码确认】

        [root@iz2ze8e1dj06n0wjqj19n2z ~]# chkconfig --level 2345 mysqld on
        Note: Forwarding request to 'systemctl enable mysqld.service'.
        ```

4. 初始配置后正常运行/登录mysql:`mysql -u root -p`

        ```bash
        mysql -u root -p
        【此处输入密码】
        [root@iz2ze8e1dj06n0wjqj19n2z ~]# mysql -u root -p
        Enter password: 
        Welcome to the MySQL monitor.  Commands end with ; or \g.
        Your MySQL connection id is 2
        Server version: 5.6.43 MySQL Community Server (GPL)

        Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.

        Oracle is a registered trademark of Oracle Corporation and/or its
        affiliates. Other names may be trademarks of their respective
        owners.

        Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

        mysql> 
        ```

5. 退出 mysql 命令行界面:`exit` 回车和 `ctrl+d`

        ```bash
        mysql> exit
        Bye
        mysql> ^DBye
        ```

### 数据库表操作&管理
1. 查看数据库列表:`show databases;`

        ```sql
        mysql> show databases;
        +--------------------+
        | Database           |
        +--------------------+
        | information_schema |
        | mysql              |
        | performance_schema |
        +--------------------+
        3 rows in set (0.00 sec)

        mysql> 
        ```

2. 创建数据库:`CREATE DATABASE [数据库名];`

        ```sql
        mysql> CREATE DATABASE dns;
        Query OK, 1 row affected (0.00 sec)
        ```

3. 使用数据库:`use [数据库名];`

        ```sql
        mysql> use dns;
        Database changed
        ```

4. 查看数据库的表列表:`show tables;`

        ```sql
        mysql> show tables;
        Empty set (0.01 sec)
        ```

5. 创建用户:`CREATE USER '[用户名]'@'localhost' IDENTIFIED BY '[用户密码]';`

        ```sql
        mysql> CREATE USER 'root'@'localhost' IDENTIFIED BY '111111';
        Query OK, 0 rows affected (0.01 sec)

        [root@iz2ze8e1dj06n0wjqj19n2z ~]# mysql -u root -p
        Enter password: 111111
        ```

6. 给用户赋权:`GRANT CREATE,DROP,ALTER,INSERT,UPDATE,SELECT,DELETE,INDEX ON [数据库名].* TO '[用户名]'@'localhost';`

        ```sql
        mysql> GRANT CREATE,DROP,ALTER,INSERT,UPDATE,SELECT,DELETE,INDEX ON dns.* TO 'root'@'localhost';
        Query OK, 0 rows affected (0.01 sec)
        mysql> FLUSH PRIVILEGES; # 刷新权限
        Query OK, 0 rows affected (0.01 sec)
        ```

7. 创建数据库表:`CREATE TABLE [表名]([字段1], [字段2], [字段3]……);`

        ```sql
        CREATE TABLE employee (
        employee_id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
        last_name VARCHAR(30) NOT NULL,
        first_name VARCHAR(30) NOT NULL,
        email VARCHAR(100) NOT NULL,
        hire_date DATE NOT NULL,
        notes MEDIUMTEXT,
        PRIMARY KEY (employee_id),
        INDEX (last_name),
        UNIQUE (email)
        )
        ENGINE=InnoDB
        DEFAULT CHARSET = utf8; # 修改数据库表默认编码方式
        # 遇到问题:修改编码格式后,UNIQUE的那个字段长度太长,超过索引支持
        ```

8. 修改数据库&表默认编码:[参考](https://www.cnblogs.com/shootercheng/p/5836657.html )

        ```sql
        mysql> show variables like 'character_set_database';
        +------------------------+--------+
        | Variable_name          | Value  |
        +------------------------+--------+
        | character_set_database | latin1 |
        +------------------------+--------+
        1 row in set (0.00 sec)

        create database <数据库名> character set utf8; # 创建数据库时添加字符编码设置
        create table tb_books (
            name varchar(45) not null,
            price double not null,
            bookCount int not null,
            author varchar(45) not null ) default charset = utf8; # 创建表时添加字符编码设置

        alter database <数据库名> character set utf8; # 修改数据库字符编码
        alter table <表名> character set utf8; # 修改表字符编码
        alter table <表名> change <字段名> <字段名> <类型> character set utf8; # 修改字段字符编码【这里就是要重写两遍字段名】
        alter table user change username username varchar(20) character set utf8 not null;
        # PS:修改编码格式时,若仅修改数据库编码,对于已经建好的表,编码格式不会改变,只对新建的表有用;所以对于已经建好的表,一定要修改到字段才可以,仅修改数据库和表还不行
        ```

9. 添加&修改&删除唯一约束:[MySQL 唯一约束 (UNIQUE KEY)](http://c.biancheng.net/view/2445.html);[MySQL 创建表多个字段的唯一约束](https://blog.csdn.net/john1337/article/details/84141087)

        ```sql
        # 1. 在创建表时设置唯一约束:在定义完列之后直接使用 UNIQUE 关键字指定唯一约束,语法规则:
        # <字段名> <数据类型> UNIQUE
        mysql> CREATE TABLE tb_dept2
            -> (
            -> id INT(11) PRIMARY KEY,
            -> name VARCHAR(22) UNIQUE, # 唯一约束
            -> location VARCHAR(50)
            -> );
        # 2. 在修改表时添加唯一约束:在修改表时添加唯一约束的语法格式为:
        # ALTER TABLE <数据表名> ADD CONSTRAINT <唯一约束名> UNIQUE(<列名>);
        mysql> ALTER TABLE tb_dept1
            -> ADD CONSTRAINT unique_name UNIQUE(name);
        # 3. 删除唯一约束:在 MySQL 中删除唯一约束的语法格式如下:
        # ALTER TABLE <表名> DROP INDEX <唯一约束名>;
        mysql> ALTER TABLE tb_dept1
            -> DROP INDEX unique_name;
        # 4. 多字段组合唯一约束,mysql 提供了两种方式:
        alter table xx add unique key no_account(no,collection_account) # unique key
        alter table xx add unique no_account_index(no,collection_account); # unique index
        ```

10. 唯一约束长度太长导致建表出错:`修改 mysql 全局配置并删表重建添加表动态属性`;参考[MySQL唯一约束长度限制](https://blog.51cto.com/13120271/2315189);参考[修改Mysql索引长度限制](https://blog.csdn.net/u010719917/article/details/70598813):对row_format为dynamic格式 ,可以指定索引列长度大于767 bytes。但是索引列总长度的不能大于3072 bytes的限制仍然存在;参考[mysql改变innodb_large_prefix](http://www.voidcn.com/article/p-uoferwcl-bwa.html) 默认约束长度为 767 字节,来源是因为之前 utf8 256*3字节-1 = 767 字节。可以通过修改 innodb_large_prefix 参数扩展至 3072 字节,文章说:一般情况下不建议使用这么长的索引,对性能有一定影响;最后这篇文章提出来的最终版原因是:MySQL 索引只支持767个字节,utf8mb4 每个字符占用4个字节,所以索引最大长度只能为191个字符,即varchar(191),若想要使用更大的字段,mysql需要设置成支持数据压缩,并且修改表属性 row_format ={DYNAMIC|COMPRESSED}。最后搞定顺序:1. 在 MySQL 命令行中:`SET GLOBAL innodb_file_format = Barracuda;`, `SET GLOBAL innodb_file_per_table = ON;`, `SET GLOBAL  innodb_large_prefix=on;`,修改全局配置;2. 然后删除需要建索引的表后,重建表在最后添加:`ROW_FORMAT = DYNAMIC; – 或COMPRESSED(在CREATE结束时)`

        ```sql
        mysql> show variables like 'innodb_large_prefix';
        +---------------------+-------+
        | Variable_name       | Value |
        +---------------------+-------+
        | innodb_large_prefix | OFF   |
        +---------------------+-------+
        1 row in set (0.00 sec)

        mysql> set global innodb_large_prefix=on; # 修改全局配置
        Query OK, 0 rows affected (0.00 sec)

        mysql> show variables like 'innodb_large_prefix';
        +---------------------+-------+
        | Variable_name       | Value |
        +---------------------+-------+
        | innodb_large_prefix | ON    |
        +---------------------+-------+
        1 row in set (0.00 sec)

        CREATE TABLE `domain` (
        ……
        ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; # 创建表添加字段
        ```

11. 清空数据表中数据:`delete from [表名];` 或者 `truncate table [表名];`  [TRUNCATE 和 DELETE 的区别](https://blog.csdn.net/stail111/article/details/5718771)不带where参数的delete语句可以删除mysql表中所有内容,使用truncate table也可以清空mysql表中所有内容;效率上truncate比delete快,但truncate删除后不记录mysql日志,不可以恢复数据;delete的效果有点像将mysql表中所有记录一条一条删除到删完,保留mysql表的结构;而truncate相当于重新创建了这个表,所有的状态都相当于新表。

        ```sql
        delete from 表名;
        truncate table 表名;
        ```

12. 删除数据库&表:`drop database [库名];` 和 `DROP TABLE [表名];`

        ```sql
        DROP TABLE table_name ;

        mysql> drop database dns;
        Query OK, 6 rows affected (0.36 sec)

        mysql> show databases;
        +--------------------+
        | Database           |
        +--------------------+
        | information_schema |
        | mysql              |
        | performance_schema |
        +--------------------+
        3 rows in set (0.01 sec)
        ```