一、索引
1、查看表索引
show keys from test_table
2、删除索引或唯一约束UNIQUE KEY
drop index crisis_id on test_table;
ALTER TABLE test_tab1 DROP KEY udx_entry_pk_id_creator;
3、添加索引
建表添加索引
(1)普通索引
普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。因此,应该只为那些最经常出现在查询条件(WHERE column = …)或排序条件(ORDER BY column)中的数据列创建索引
create table t_test_table(
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(20) DEFAULT NULL COMMENT '名称',
`sex` varchar(2) DEFAULT NULL COMMENT '性别',
`sql_detail` text DEFAULT NULL COMMENT '执行的SQL',
`comm` text DEFAULT NULL COMMENT '长文本',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
index idx_name(name)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试表'
(2)唯一索引
如果能确定某个数据列将只包含彼此各不相同的值,在为这个数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引.
这么做的好处:一是简 化了MySQL对这个索引的管理工作,这个索引也因此而变得更有效率;二是MySQL会在有新记录插入数据表时,自动检查新记录的这个字段的值是否已经在 某个记录的这个字段里出现过了;如果是,MySQL将拒绝插入那条新记录
create table t_test_table(
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(20) DEFAULT NULL COMMENT '名称',
`sex` varchar(2) DEFAULT NULL COMMENT '性别',
`sql_detail` text DEFAULT NULL COMMENT '执行的SQL',
`comm` text DEFAULT NULL COMMENT '长文本',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
unique index udx_name(`name`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试表'
(3)全文索引
文本字段上的普通索引只能加快对出现在字段内容最前面的字符串(也就是字段内容开头的字符)进行检索操作。如果字段里存放的是由几个、甚至是多个单词构成 的较大段文字,普通索引就没什么作用了。这种检索往往以LIKE %word%的形式出现,这对MySQL来说很复杂,如果需要处理的数据量很大,响应时间就会很长。
这类场合正是全文索引(full-text index)可以大显身手的地方。在生成这种类型的索引时,MySQL将把在文本中出现的所有单词创建为一份清单,查询操作将根据这份清单去检索有关的数 据记录。注解:InnoDB数据表不支持全文索引。
create table t_test_table(
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(20) DEFAULT NULL COMMENT '名称',
`sex` varchar(2) DEFAULT NULL COMMENT '性别',
`sql_detail` text DEFAULT NULL COMMENT '执行的SQL',
`comm` text DEFAULT NULL COMMENT '长文本',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
fulltext index index_no(id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试表'
(4)多列索引
索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引。这种索引的特点是MySQL可以有选择地使用一个这样的索引。如果查询操作只需要用到columnA数据列上的一个索引,就可以使 用复合索引INDEX(columnA, columnB)
create table t_test_table(
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(20) DEFAULT NULL COMMENT '名称',
`sex` varchar(2) DEFAULT NULL COMMENT '性别',
`sql_detail` text DEFAULT NULL COMMENT '执行的SQL',
`comm` text DEFAULT NULL COMMENT '长文本',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
fulltext index index_no(name,sex)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试表'
(5)主索引
必须为主键字段创建一个索引,这个索引就是所谓的”主索引”。主索引与唯一索引的唯一区别是:前者在定义时使用的关键字是 PRIMARY而不是UNIQUE。
create table t_test_table(
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(20) DEFAULT NULL COMMENT '名称',
`sex` varchar(2) DEFAULT NULL COMMENT '性别',
`sql_detail` text DEFAULT NULL COMMENT '执行的SQL',
`comm` text DEFAULT NULL COMMENT '长文本',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='测试表'
建表后添加索引
(1)普通索引
alter table t_test_table add index index_name(name);
或
create index index_name on t_test_table(name);
(2)唯一索引
alter table t_test_table add unique index index_name(name);
或
create unique index index_name on t_test_table(name);
(3)全文索引
alter table t_test_table add fulltext index_name(name);
或
create fulltext index index_name on t_test_table(name);
(4)多列索引
alter table t_test_table add index index_name_no(name,sex);
或
create index index_name_no on t_test_table(name,sex)
4、开启关闭索引
关闭:ALTER TABLE `test` DISABLE KEYS ;
开启:ALTER TABLE `test` ENABLE KEYS;
二、表结构修改
1、添加字段
alter table etl_mcbi_gbusiness_line_class_order_daily
add `dx_rate` decimal(30,6) COMMENT '动销率今日值',
add `dx_rate_wac` decimal(30,6) COMMENT '动销率周累计',
add `dx_rate_mac` decimal(30,6) COMMENT '动销率月累计';
2、修改字段not null改为null
ALTER TABLE test_property MODIFY name int(10) unsigned DEFAULT '0' COMMENT '测试字段';
3、删除列
alter table test2 drop column test_time1;
4、修改列名
alter table test2 CHANGE content content1 text;
5、修改列类型
alter table test2 MODIFY COLUMN job_id varchar(512);
三、常用sql
1、查询
select * from tab1 where 1=1 limit 10;
2、插入数据
insert into white_user_info (name,spelling_name,mail ) values('wang','wang','wang @163.com ');
3、删除数据
delete from white_user_info where name='wang'
4、更新数据
update white_user_info set name='wang1',mail='wangshida@169.com' where name='wang'
批量更新Sql
UPDATE table_info111
SET name = CASE id
when 1 then 'test1'
when 2 then 'test2'
END
WHERE id IN (1,2);
两个表合并,更细左表一个字段来源于另一张表
update glink_tmp_job_info br,glink_tmp_tmp_tmp st set br.menu_id = st.menu_id where br.job_id = st.id;
5、远程连接mysql
mysql -h 127.0.0.1 -uroot -p123456 databases
6、查看有没有开启binlog
show variables like 'log_bin%';
6.1开启binlog
查找mysql路径:mysql --help | grep 'Default options' -A 1
得到优先加载 /etc/my.cnf 和/etc/mysql/my.cnf
修改配置文件/etc/mysql/my.cnf
===================================
#设置日志三种格式:STATEMENT、ROW、MIXED binlog_format=ROW #设置日志路径,注意路经需要mysql用户有权限写 log-bin=mysql-bin #配置serverid server-id=1 #设置binlog清理时间 expire_logs_days=7 #binlog每个日志文件大小 max_binlog_size=100m #binlog缓存大小 binlog_cache_size=4m #最大binlog缓存大小 max_binlog_cache_size=512m
==================================
重启,然后查看binlog是否开启
service mysql restart
6.2常用binlog命令
查看所有binlog列表: show master logs
查看最新的binlog:show master status
刷新log日志,产生新的binlog文件:flush logs
清空所有binlog日志:reset master
查看binlog格式:show variables like 'binlog_format'
binlog存放路径:cd /var/lib/mysql
查询binlog信息:show binlog events in 'mysql-bin.000001' from 4 limit 5
下载非二进制binlog文件(habo-new01):mysqlbinlog --read-from-remote-server --host=??? --user=??? --password=??? mysql-bin.000984 > mysql-bin.000984
下载二进制binlog文件:mysqlbinlog --host=??? --user=??? --password=??? --read-from-remote-server --raw --result-file=/root/ mysql-bin.003349
mysqlbinlog -h<连接地址> -u<用户名> -p<密码> --read-from-remote-server --raw mysql-bin.******
查看二进制binlog文件内容:mysqlbinlog --base64-output=DECODE-ROWS -v ./mysql-bin.003349 | head -n 10
mysqlbinlog --base64-output=DECODE-ROWS -v ./mysql-bin.022296 | grep -C 20 27966798647001472
mysqlbinlog --host=127.0.0.1 --user=user --password=password --read-from-remote-server --base64-output=DECODE-ROWS -v mysql-bin.0000|head -n 20
7、查询表行数
小表:select count(1) from tabl1
大表-上亿表:select TABLE_NAME, TABLE_ROWS from INFORMATION_SCHEMA.tables where TABLE_SCHEMA = 'urobot' and TABLE_NAME='tab111';
select TABLE_NAME, TABLE_ROWS from INFORMATION_SCHEMA.PARTITIONS where TABLE_SCHEMA = 'urobot' and TABLE_NAME='tab111';
大表-上亿表:查最大自增id,最小自增id,相减得出大概行数
select id from test_table order by id asc limit 1;
select id from test_table order by id desc limit 1;
查询表大小
use information_schema;
select concat(round(sum(DATA_LENGTH/1024/1024),2),'MB') as data from TABLES where table_schema='库' and table_name='表名';
8、查询数据导出到文件
mysql -h ??? -u?? -p??? dpl -e "select t.task_id from ??? t where t.data_time >= '2021-09-22 12:00:01' and t.running_status = 7" > /apps/home/worker/wangshida/1
mysql字段中存储换行符,导致导出exl异常。查询sql加如下转换操作
REPLACE(REPLACE(tab4.entry_parm, CHAR(10),' '), CHAR(13),' ') as entry_parm,
导出数据(适合小表)
mysqldump -h 127.0.0.1 -uroot -p --default-character-set=utf8 dbname table_name > test_table.sql
导入数据
mysql -h 127.0.0.1 -uroot -p --default-character-set=utf8 dbname < test_table.sql
9、查询字段不包含某字符串
select * from task where source ='dpl' and deleted=0 and task_config like '%"maxRetryNum":0%' and locate("dpl_init",name) = 0;
10、日期转换
10.1 字符串转日期
SELECT STR_TO_DATE('20210114163600','%Y%m%d %H%i%s') as 'temp_date';
10.2日期转字符串
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s');
10.3时间转时间戳
select unix_timestamp(now());
10.4字符串转时间戳
select unix_timestamp('2019-01-20');
10.5 获取前N天时间戳
select UNIX_TIMESTAMP(NOW() - INTERVAL 3 DAY)*1000;
10.6时间戳转字符串
select from_unixtime(1451997924,'%Y-%d');
11、字符串替换
UPDATE test.test_table set url=REPLACE(url, "https://www.robots.com", "https://www.robots2.com") where add_time>'2022-06-04';
12、复制数据
(1)拷贝全量数据从tab1到tab2
insert into tab2 select * from tab1
(2)指定字段拷贝
insert into tab2 (name, price) SELECT name, price from tab1 where id=5
(3)拷贝数据同时建表
create table table3 select * from table1
(4)只拷贝表结构,不拷贝数据
create table table4 like table1
13、查询表描述信息
SELECT TABLE_SCHEMA AS TABLE_CAT, NULL AS TABLE_SCHEM, TABLE_NAME, CASE WHEN TABLE_TYPE='BASE TABLE' THEN CASE WHEN TABLE_SCHEMA = 'mysql' OR TABLE_SCHEMA = 'performance_schema' THEN 'SYSTEM TABLE' ELSE 'TABLE' END WHEN TABLE_TYPE='TEMPORARY' THEN 'LOCAL_TEMPORARY' ELSE TABLE_TYPE END AS TABLE_TYPE, TABLE_COMMENT AS REMARKS, NULL AS TYPE_CAT, NULL AS TYPE_SCHEM, NULL AS TYPE_NAME, NULL AS SELF_REFERENCING_COL_NAME, NULL AS REF_GENERATION FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'urobot' AND TABLE_NAME LIKE 'ss_robot_task' ORDER BY TABLE_TYPE, TABLE_SCHEMA, TABLE_NAME
四、Sql分析
1、sql分析
explain select * from app_bicore_pb_order_daily where dt=20190709
id:这是SELECT的查询序列号
select_type:select_type就是select的类型,可以有以下几种:
SIMPLE:简单SELECT(不使用UNION或子查询等)
PRIMARY:最外面的SELECT
UNION:UNION中的第二个或后面的SELECT语句
DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询
UNION RESULT:UNION的结果。
SUBQUERY:子查询中的第一个SELECT
DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询
DERIVED:导出表的SELECT(FROM子句的子查询)
table:显示这一行的数据是关于哪张表的
type:这列最重要,显示了连接使用了哪种类别,有无使用索引,是使用Explain命令分析性能瓶颈的关键项之一。
结果值从好到坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,得保证查询至少达到range级别,最好能达到ref,否则就可能会出现性能问题。
possible_keys:列指出MySQL能使用哪个索引在该表中找到行
key:显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL
key_len:显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。使用的索引的长度。在不损失精确性的情况下,长度越短越好
ref:显示使用哪个列或常数与key一起从表中选择行。
rows:显示MySQL认为它执行查询时必须检查的行数。
Extra:包含MySQL解决查询的详细信息,也是关键参考项之一。
Distinct :一旦MYSQL找到了与行相联合匹配的行,就不再搜索了
Not exists:MYSQL 优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了
Range checked for each Record(index map:#)
没有找到理想的索引,因此对于从前面表中来的每一 个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一
Using filesort
看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来 排序全部行
Using index
列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表 的全部的请求列都是同一个索引的部分的时候
Using temporary
看到这个的时候,查询需要优化了。这 里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上
Using where
使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index, 这就会发生,或者是查询有问题
其他一些Tip:
当type 显示为 “index” 时,并且Extra显示为“Using Index”, 表明使用了覆盖索引。
五、运维
1、用户操作
1.1、 创建用户
%:所有ip都可访问
create user 'username'@'%' identified by 'password';
1.2、删除用户
drop user '用户名'@'IP地址';
1.3、修改用户
rename user '用户名'@'IP地址' to '新用户名'@'IP地址';
1.4、修改密码
set password for '用户名'@'IP地址'=Password('新密码');
1.5、查看用户权限
show grants for '用户'@'IP地址'
2、权限管理
2.1、授权 alex用户仅对db1.t1文件有查询、插入和更新的操作 grant select ,insert,update on db1.t1 to "alex"@'%';
2.2、alex用户对db1数据库中的文件执行任何操作
grant all privileges on db1.* to "flink"@'%';
2.3、alex用户对所有数据库中文件有任何操作 grant all privileges on *.* to "alex"@'%';
2.4、取消alex用户对db1的t1文件的任意操作 revoke all on db1.t1 from 'alex'@"%"; 2.5、取消来自远程服务器的alex用户对数据库db1的所有表的所有权限 revoke all on db1.* from 'alex'@"%"; 2.6、取消来自远程服务器的alex用户所有数据库的所有的表的权限 revoke all privileges on *.* from 'alex'@'%';
3、数据备份 (1) 备份:数据表结构 mysqdump -u root -d db1 > db1.sql -p (2)导入现有的数据到某个数据库 先创建一个新的数据库 create database db10; 将已有的数据库文件导入到db10数据库中 mysqdump -u root -d db10 < db1.sql -p
(3)仅导出数据到sql
mysqldump -uroot -pxxxxx -hxxxxx -P3306 --no-create-info --databases test --tables task_metadata > ~/data.sql
六、常用优化
1、in 和 not in 要慎用,否则会导致全表扫描,连续可用between 替代
不连续用select num from a where exists(select 1 from b where num=a.num)
2、避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描字段建立时,空间就固定了不管是否插入值(NULL也包含在内)
3、应尽量避免在 where 子句中使用 != 或 <> 操作符,否则将引擎放弃使用索引而进行全表扫描。
4、应尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描
select id from t where num=10 or Name = 'admin'
替换为select id from t where num = 10 union all select id from t where Name = 'admin'
5、Like也会导致全表扫描
6、在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。
然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。
select id from t where num = @num
可以改为强制查询使用索引:
select id from t with(index(索引名)) where num = @num
7、避免在where子句对字段进行表达式操作,将会导致全表扫描
select id from t where num/2 = 100 可改为
select id from t where num = 100*2
8、应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。
select id from t where substring(name,1,3) = ’abc’ -–name以abc开头的id
select id from t where datediff(day,createdate,’2005-11-30′) = 0 -–‘2005-11-30’ --生成的id
替换为
select id from t where name like 'abc%'
select id from t where createdate >= '2005-11-30' and createdate < '2005-12-1'
9、不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
10、在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
11、Update 语句,如果只更改1、2个字段,不要Update全部字段,否则频繁调用会引起明显的性能消耗,同时带来大量日志。
12、对于多张大数据量(这里几百条就算大了)的表JOIN,要先分页再JOIN,否则逻辑读会很高,性能很差。
13、select count(*) from table;这样不带任何条件的count会引起全表扫描,并且没有任何业务意义,是一定要杜绝的。
14、索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。
一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有 必要。
15、尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连 接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
16、尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
17、任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
18、避免频繁创建和删除临时表,以减少系统表资源的消耗。临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件, 最好使用导出表。
19、在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
20、尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。
21、尽量避免大事务操作,提高系统并发能力。
22、拆分大的 DELETE 或INSERT 语句,批量提交SQL语句
七、函数
unix_timestamp() 自'1970-01-01 00:00:00'与指定时间的秒数差
CAST (expression AS data_type) 用于将某种数据类型的表达式显式转换为另一种
expression:任何有效的SQServer表达式。
AS:用于分隔两个参数,之前需处理之后处理结果
data_type:目标系统所提供的数据类型
avg(): 函数返回组中各值的平均数
sum(): 函数返回组中各值之和
count(): 函数返回匹配指定条件的行数
Max(): 函数返回表达式的最大值
Min(): 函数返回表达式的最小值
日期函数
getdate(): 函数返回当前时间
datepart(datepart, date): 函数返回时间的某一部分
DATE_ADD(aaa.createtime,INTERVAL 2 DAY) 函数在日期中添加或减去指定的时间间隔
datediff(日期类型dd yy , startdate, enddate): 函数返回两个日期之间的天数
FROM_UNIXTIME(1508256000,'%Y年%m月%d') 数据库存储数字转换为日期format字符串格式化date值
UNIX_TIMESTAMP(aaa.datekey) 1970-01-01 00:00:00到当前时间的秒数差
cast(stock.datekey as string) 日期类型转为String
日期类型参考
DATEDIFF(FROM_UNIXTIME(aaa.datekey), from_unixtime(unix_timestamp(cast(stock.datekey as string)))
数学函数
abs(): 函数返回绝对值
ceiling(): 函数返回大于等于该数的最小整数
floor(): 函数返回小于等于该数的最大整数
rand(): 函数返回一个0-1之间的随机数
round(value,decimals): 函数将一个数value舍入精确到小数点后几位小数
字符串函数
charindex(子串, 目标串[ , start] ) 函数返回子串在目标串中最先出现位置的index
left(expression, number): 函数返回目标串的左边指定长度的子串
right(expression, number): 函数返回目标串的右边指定长度的子串
ltrim(expression): 函数去除字符串左边的空格
rtrim(expression): 函数去除字符串右边的空格
substring(expression, start, length): 函数返回目标串的一个子串,起始位置和长度
upper(): 函数将目标串中的所有字符转化为大写字母
lower(): 函数将目标串中的所有字符转化为小写字母
isnull(expression, value): 如果expression是null的话,则返回value值, 否则返回expression
NVL( string1, replace) 如果有数据的话返回string1,没有的话用replace替代