MySQL replace语句

MySQL replace语法

REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
{VALUES | VALUE} (value_list) [, (value_list)] ...
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
SET assignment_list
REPLACE [LOW_PRIORITY | DELAYED]
[INTO] tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[(col_name [, col_name] ...)]
SELECT ...
value:
{expr | DEFAULT}
value_list:
value [, value] ...
assignment:
col_name = value
assignment_list:
assignment [, assignment] ...

REPLACE的工作方式与INSERT完全相同,不同的是,如果表中的旧行与PRIMARY KEY或UNIQUE索引中的新行具有相同的值,则在插入新行之前删除旧行。

REPLACE是MySQL对SQL标准的扩展。它要么插入,要么删除和插入。

DELAYED插入和替换在MySQL 5.6中已被弃用。MySQL 5.7不支持DELAYED。服务器识别但忽略DELAYED关键字,将替换作为非延迟替换处理,并生成er_warn_legacy_syntax_convert警告。(不再支持REPLACE DELAYED。语句被转换为REPLACE。)DELAYED关键字将在未来的版本中被删除。

只有当一个表有一个主键或唯一索引时,REPLACE才有意义。否则,它将等价于INSERT,因为没有索引可用于确定新行是否与另一行重复。

所有列的值都取自REPLACE语句中指定的值。所有缺失的列都被设置为默认值,就像INSERT一样。不能引用当前行的值并在新行中使用它们。如果使用诸如SET col_name = col_name + 1这样的赋值,对右边列名的引用将被视为DEFAULT(col_name),因此赋值等价于

SET col_name = DEFAULT(col_name) + 1。

要使用REPLACE,必须同时拥有表的INSERT和DELETE特权。

如果显式替换生成的列,则唯一允许的值是DEFAULT

REPLACE支持显式分区选择,使用partition关键字和分区、子分区或两者的相对名称列表。与INSERT一样,如果不可能将新行插入到任何这些分区或子分区中,则REPLACE语句将失败,并出现Found a row not matching the given partition set错误。

REPLACE语句返回一个计数,以指示受影响的行数。这是删除和插入的行之和。如果对于单行REPLACE计数为1,则插入一行,不删除任何行。如果计数大于1,则在插入新行之前删除一个或多个旧行。如果表包含多个唯一索引,并且新行在不同唯一索引中重复不同旧行的值,则单个行可以替换多个旧行。

受影响的行数可以很容易地确定REPLACE是只添加了一行,还是也替换了任何行:检查计数是否为1(添加)或更大(替换)。

如果您使用的是C API,受影响的行数可以通过mysql_affected_rows()函数获得。

您不能在子查询中替换一个表并从同一表中进行选择

MySQL对于replace(和load data … replace)使用如下算法:
1.尝试将新行插入到表中
2.当因为主键或唯一索引出现重复键错误而插入失败时:
a.从表中删除具有重复键值的冲突行
b.请再次将新行插入表中

在出现重复键错误的情况下,存储引擎可能会将REPLACE作为更新而不是删除加插入来执行,但语义是相同的。除了存储引擎增加Handler_xxx状态变量的方式不同之外,没有用户可见的影响

因为REPLACE …SELECT语句的结果依赖于SELECT语句中的行顺序,并且这种顺序不能总是得到保证,当记录这些语句时,主服务器和从服务器可能出现分歧。基于这个理由,replace … select语句对于基于语句的复制来说被标记为不安全。当使用基于语句的模式时,这些语句会在错误日志中产生一个警告,而当使用MIXED模式时,这些语句会使用基于行的格式写入二进制日志。

当修改没有分区的现有表以适应分区时,或者在修改已分区表的分区时,可以考虑修改表的主键(参见22.6.1节,分区键、主键和唯一键)。您应该注意,如果这样做,REPLACE语句的结果可能会受到影响,就像修改非分区表的主键一样。考虑下面的CREATE table语句创建的表:

CREATE TABLE test (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
data VARCHAR(64) DEFAULT NULL,
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);

当我们创建这个表并运行mysql客户机中显示的语句时,结果如下所示:

mysql> REPLACE INTO test VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.03 sec)

mysql> REPLACE INTO test VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 2 rows affected (0.10 sec)

mysql> SELECT * FROM test;
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
1 row in set (0.01 sec)

现在我们创建第二个表,与第一个表几乎相同,除了主键现在是包含2列的复合主键,如下所示(强调文本):

CREATE TABLE test2 (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
data VARCHAR(64) DEFAULT NULL,
ts TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id, ts)
);

当我们在test2上运行与在原始测试表上相同的两个REPLACE语句时,我们得到了不同的结果:

mysql> REPLACE INTO test2 VALUES (1, 'Old', '2014-08-20 18:47:00');
Query OK, 1 row affected (0.06 sec)

mysql> REPLACE INTO test2 VALUES (1, 'New', '2014-08-20 18:47:42');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM test2;
+----+------+---------------------+
| id | data | ts                  |
+----+------+---------------------+
|  1 | Old  | 2014-08-20 18:47:00 |
|  1 | New  | 2014-08-20 18:47:42 |
+----+------+---------------------+
2 rows in set (0.01 sec)

这是因为,当运行test2时,id和ts列值必须与现有行的值匹配,以便替换该行;否则,插入一行。

使用MyISAM等存储引擎(使用表级锁)的REPLACE语句影响分区表,只要不更新表分区列,则只锁那些包含匹配REPLACE语句WHERE子句的行的分区;否则锁定整个表。(对于像InnoDB这样使用行级锁的存储引擎,不会发生分区锁。)

MySQL load data加载数据

load data 加载数据
load data infile语法如下:

LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'
[REPLACE | IGNORE]
INTO TABLE tbl_name
[PARTITION (partition_name [, partition_name] ...)]
[CHARACTER SET charset_name]
[{FIELDS | COLUMNS}
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
[IGNORE number {LINES | ROWS}]
[(col_name_or_user_var
[, col_name_or_user_var] ...)]
[SET col_name={expr | DEFAULT},
[, col_name={expr | DEFAULT}] ...]


load data infile语句从文本文件中读取数据加载到数据表中有非常高的效率。为了将数据从表中写入文本文件可以使用select … into outfile,为了将数据从文本文件加载回数据表,使用load data infile语句。对于这两种语句fields与lines子句是相同的。这两个子句是可选的,如果两个子句被指定那么fields必须在lines的前面。

也可以使用mysqlimport工具来加载数据文件,它是通过发送oad data infile语句给服务器来进行操作。mysqlimport的–local选项会导致mysqlimport从客户端主机上读取数据文件。如果客户端和服务器支持压缩协议使用–compress选项将得到更好的性能。

文件名必须以字面值字符串的形式给出。在Windows上,在路径名中指定反斜杠为正斜杠或双反斜杠。character_set_filesystem系统变量控制文件名的解释。

LOAD DATA支持使用带有一个或多个以逗号分隔的分区、子分区或是同时指定分区与子分区的名称列表的partition选项进行显式分区选择。使用此选项时,如果文件中的任何行不能插入到列表中指定的任何分区或子分区中,则语句会失败,错误为Found a row not matching the给定的分区集。

对于使用MyISAM等使用表锁的存储引擎的分区表,LOAD DATA不能删除任何分区锁。这不适用于使用行级锁的存储引擎的表,比如InnoDB

服务器使用由character_set_database系统变量指示的字符集来解释文件中的信息。SET NAMES和character_set_client的设置不会影响输入的解释。如果输入文件的内容使用与默认不同的字符集,通常最好使用character set子句指定文件的字符集。二进制字符集指定不转换。

LOAD DATA INFILE将文件中的所有字段解释为具有相同的字符集,而不考虑字段值加载到的列的数据类型。为了正确解释文件内容,您必须确保它是用正确的字符集编写的。例如,如果你写一个数据文件使用mysqldump -T或者在mysql中发出SELECT…INTO OUTFILE语句,一定要使用–default-character-set选项输出时所使用的字符集在当文件被LOAD DATA INFILE加载时将要使用。

如果使用LOW_PRIORITY, LOAD DATA语句的执行将被延迟,直到没有其他客户端从表中读取数据。这只会影响仅使用表级锁的存储引擎(如MyISAM、memory和merge)。

如果MyISAM表指定CONCURRENT来满足并发插入条件的(即,它中间不包含空闲块),那么在执行LOAD DATA时,其他线程可以从表中检索数据。即使没有其他线程同时使用这个表,这个选项也会略微影响LOAD DATA的性能。

使用基于行的复制,无论MySQL版本如何,都可以并发复制。使用基于语句的复制,在MySQL 5.5.1之前不会执行并发复制(见Bug #34628)。

LOCAL关键字影响文件的预期位置和错误处理,如后面所述。只有当服务器和客户机都配置为允许LOCAL时,LOCAL才能工作。例如,如果mysqld在启动时禁用了local_infile系统变量,那么LOCAL就不起作用

local关键字的影响期望在文件中的何处被找到:
.如果local关键字被指定,通过客户端主机上的客户端程序来读取文件并发送给服务器。这个文件可以被指定完全路径名来指定精确位置。如果指定相对路径名,这将会解析成启动客户端程序目录的相对路径。

当使用load data local时,在服务器的临时目录中会创建一个文件副本。这不是由tmpdir或slave_load_tmpdir的值决定的目录,而是操作系统的临时目录,并且在MySQL服务器中不能配置(通常系统临时目录在linux系统中是/tmp,在windows中是c:\windows\temp)。如果临时目录没有足够的空间可能会造成load data local语句失败。

.如果local关键字没有指定,那么数据文件必须存储在服务器上并且服务器可以直接读取。服务器使用以下规则来定位文件:

.如果文件名是绝对路径名,服务器将按照给定的方式使用它。

.如果文件名是包含一个或多个前导组件的相对路径名,服务器将相对于服务器的数据目录搜索该文件。

.如果文件名中没有给出前导组件,服务器将在默认数据库的数据库目录中查找该文件。

在非local情况下,这些规则意味着从服务器的数据目录中读取名为./myfile.txt的文件,而从默认数据库的数据库目录中读取名为myfile.txt的文件。例如,如果db1是默认数据库,那么下面的LOAD DATA语句将从db1的数据库目录中读取文件data.txt,即使该语句显式地将文件加载到db2数据库中的一个表中:

LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table;

非local加载操作读取位于服务器上的文本文件。出于安全原因,这些操作要求您拥有FILE特权。非local加载操作受secure_file_priv系统变量设置的影响。如果变量值是非空目录名,则要加载的文件必须位于该目录中。如果变量值为空(不安全),则该文件只需要由服务器读取。

使用LOCAL比让服务器直接访问文件要慢一些,因为文件的内容必须通过客户机连接发送到服务器。另一方面,您不需要FILE特权来加载本地文件。

local也会影响错误的处理:
.使用load data infile,数据解释和重复键错误终止操作。
.使用load data local infile 数据解释和重复键错误成为警告,操作继续进行,因为服务器没有办法在操作过程中停止文件传输。对于重复键错误,这就相当于指定了IGNORE。

REPLACE和IGNORE关键字控制对在唯一键值上存在与现有行有重复的输入行的处理:
.如果指定replace,输入行将替换存在行。换句话说,与现有行的主键或唯一索引有相同的值。

.如果指定ignore,与现有行的唯一键值重复的行会被丢弃。

.如果没有指定这些选项,那么依据是否指定了local来决定。在没有指定local时,当找到重复键值时会报错且文件中剩余的内容会被忽略。当指定local时,默认的行为与指定了ignore是一样的,这是因为服务器不能阻止正在执行的文件传输操作。

为了在加载操作时忽略外键约束,可以在执行load data之前执行set foreign_key_checks=0语句。

如果对一个MyISAM空表执行load data infile操作,那么所有非唯一索引将在单独的一个批处理中创建(类似于repair table)。通常来说,当有许多索引的情况下这将使load data infile操作更快。在一些极端的情况下,在加载数据文件之前可以执行alter table … disable keys来禁用索引,在加载数据文件之后执行alter table .. enable kyes来重建索引这要比创建索引效率更高。

对于load data infile和select … into outfile语句来说fiels和lines子句的语法是相同的。这些子句是可选项,但如果都被指定的话fields必须在lines的前面。

如果指定fields子句,它的每一个子句(terminated by,[optionally] enclosed by和escaped by)也是可选项,除非你必须至少指定一个。

如果没有指定fields或lines子句,默认就和下面所写的一样:

FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'
LINES TERMINATED BY '\n' STARTING BY ''

反斜杠是SQL语句中字符串中的MySQL转义字符,因此要指定一个字面值的反斜杠,您必须指定两个反斜杠才能将值解释为单个反斜杠。转义序列’\t’和’\n’分别指定制表符和换行符

换句话说,在读取输入时,默认值导致LOAD DATA INFILE执行如下操作:
.在换行处查看行边界。
.不会跳过任何行前缀
.在制表符中将行拆分为字段
.不要期望字段用引号括起来
.将前面有转义字符\的字符解释为转义序列。例如,“\t”、“\n”、“\\”分别表示制表符、换行符、反斜杠

相反,默认值会导致select … into outfile执行如下操作
.在字段之间写制表符
.要用引号括起字段
.使用\转义字段值中出现的制表符、换行符或\实例
.在行尾写换行

如果您已经在Windows系统上生成了文本文件,您可能必须使用LINES TERMINATED BY ‘\r\n’来正确读取该文件,因为Windows程序通常使用两个字符作为行结束符。有些程序,如写字板,在写文件时可能使用\r作为行结束符。要读取这样的文件,请使用以’\r’结尾的行。

如果您想要读入的所有行都有一个您想要忽略的公共前缀,您可以使用LINES STARTING BY ‘prefix_string’来跳过该前缀和它之前的任何内容。如果某一行不包含前缀,则跳过整行。假设您发出以下语句:

load data infile '/tmp/test.txt' into table test fields terminated by ',' lines starting by 'xxx';

如果数据文件内容类似如下:

xxx"abc",1
something xxx"def",2
"ghi",3

上面数据文件执行加载后行数将是(“abc”,1)和(“def”,2)。第三行将会被跳过因为它不包含前缀。

ignore number lines选项可以用来忽略文件开头的行。例如,可以使用ignore 1 lines来跳过包含列名的首标题行:

load data infile '/tmp/test.txt' into table test ignore 1 lines;

当你使用SELECT…INTO OUTFILE与LOAD DATA INFILE一起将数据从数据库写入文件,然后稍后将文件读回数据库,这两个语句的字段和行处理选项必须匹配。否则,LOAD DATA INFILE将不能正确解释文件的内容。假设你使用SELECT…写入一个以逗号分隔的字段的文件:

select * into outfile 'data.txt' fields terminated by ',' from table2;

要将逗号分隔的文件读入,正确的语句应该是:

load data infile 'data.txt' into table table2 fields terminated by ',';

如果您尝试使用下面所示的语句读取文件,则不会工作,因为它指示LOAD DATA INFILE查找字段之间的制表符:

load data infile 'data.txt' into table table2 fields terminated by '\t';

可能的结果是,每个输入行将被解释为单个字段。

LOAD DATA INFILE可用于读取从外部来源获得的文件。例如,许多程序可以以逗号分隔值(CSV)格式导出数据,例如,行中有用逗号分隔的字段,并用双引号括起来,并使用列名的首行。如果这样一个文件中的行以回车/换行对结束,这里显示的语句说明了用于加载文件的字段和行处理选项。

LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\r\n'
IGNORE 1 LINES;

如果输入值不一定用引号括起来,请在enclosed BY关键字前使用optionally。

任何字段处理或行处理选项都可以指定一个空字符串(“)。如果不为空,则FIELDS[OPTIONALLY] ENCLOSEDBY和FIELDS ESCAPED BY值必须是单个字符。FIELDS TERMINATED BY、LINES started BY和LINES TERMINATED BY值可以多于一个字符。例如,要写以回车/换行对结尾的行,或读取包含此类行的文件,请指定lines terminated by ‘\r\n’子句。

要读取包含由%%作为行分隔符的的文件,您可以这样做

CREATE TABLE jokes
(a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
joke TEXT NOT NULL);
LOAD DATA INFILE '/tmp/jokes.txt' INTO TABLE jokes
FIELDS TERMINATED BY ''
LINES TERMINATED BY '\n%%\n' (joke);
< ?pre>
fields [optionally] enclosed by控制字段的引用。对于(select ... into outfile)输出,如果你忽略了关键字optionally,所有的字段都包含在enclosed by字符包含着。
这里显示了这样的输出示例(使用逗号作为字段分隔符):
"1","a string","100.20"
"2","a string containing a , comma","102.20"
"3","a string containing a \" quote","102.20"
"4","a string containing a \", quote and comma","102.20"

如果你指定optionally,那么enclosed by字符只用来封装字符串数据类型的值(比如char,binary,text或enum):

1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a \" quote",102.20
4,"a string containing a \", quote and comma",102.20

字段值中出现的enclosed by字符将通过在它们前面加上escaped by字符进行转义。此外,如果您指定了一个空的escaped by值,可能会无意中生成无法被LOAD DATA INFILE正确读取的输出。例如,如果转义字符为空,前面显示的输出将如下所示。注意,第四行第二个字段包含引号后面的逗号,这(错误地)似乎是结束该字段:

1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a " quote",102.20
4,"a string containing a ", quote and comma",102.20

对于输入,如果存在enclosed by 字符,则从字段值的末尾删除。(无论是否指定了optionally,这都是正确的;optionally对输入解释没有影响。)出现在enclosed by字符前的escaped by字符将被解释为当前字段值的一部分。

如果字段以enclosed by字符开头,则该字符的实例只有在后跟字段或行terminated by序列时才会被识别为终止字段值。为了避免歧义,在字段值中出现enclosed by字符的次数可以加倍,并被解释为该字符的单个实例。例如,如果指定了enclosed by ‘”‘则会像这里所示处理引号:

"The ""BIG"" boss" -> The "BIG" boss
The "BIG" boss -> The "BIG" boss
The ""BIG"" boss -> The ""BIG"" boss

fields escaped by控制如何读取或写入特殊字符
.对于输入,如果fields escaped by字符不为空,则剥离出现的该字符,并按照字面意思将下面的字符作为字段值的一部分。一些双字符序列是例外,其中第一个字符是转义字符。这些序列如下表所示(转义字符使用\)。本节稍后将描述NULL处理规则。

如果fields escaped by字符为空,则不会发生转义序列解释

.对于输出,如果fields escaped by字符不为空,则它用于在输出中作为以下字符的前缀

 .fields escaped by字符
 .fields [optionally] enclosed by字符
 .fields terminated by和lines terminated by值的第一个字符
 .ASCII 0(转义字符后面实际写的是ASCII 0,而不是零值字节)

如果fields escaped by字符为空,则不转义任何字符,NULL输出为NULL,而不是\N。指定空转义字符可能不是一个好主意,特别是如果数据中的字段值包含刚才给出的列表中的任何字符。

在某些情况下,字段和行处理选项相互作用:
.如果LINES TERMINATED BY为空字符串而FIELDS TERMINATED BY为非空字符串,则行也会以FIELDS TERMINATED BY结束。

.如果FIELDS TERMINATED BY和FIELDS ENCLOSED BY值都为空(“),则使用固定行(非分隔)格式。使用固定行格式,字段之间不使用分隔符(但仍然可以使用行结束符)。相反,读写列值时使用足够宽的字段宽度来容纳字段中的所有值。对于TINYINT、SMALLINT、MEDIUMINT、INT和BIGINT,无论声明的显示宽度是多少,字段宽度分别为4、6、8、11和20。

lines terminated by仍然用于分隔行。如果一行不包含所有字段,则将其余列设置为其默认值。如果你没有行结束符,你应该把它设置为”。在这种情况下,文本文件必须包含每一行的所有字段。

固定行格式也影响NULL值的处理,如后面所述

NULL值的处理根据所使用的FIELDS和LINES选项而不同:
.对于默认的FIELDS和LINES值,NULL被写为输出的\N字段值,而\N字段值被读为输入的NULL(假设escaped by字符是\)。
.如果FIELDS ENCLOSED BY不为空,则将包含字面值NULL的字段读取为NULL值。这不同于在fields enclosed by字符中包含的单词NULL,它被读为字符串’NULL’。
.如果fields escaped by为空,则NULL被写成单词NULL。
.使用固定行格式(当FIELDS TERMINATED BY和FIELDS ENCLOSED BY都为空时使用),NULL被写成空字符串。这将导致表中的NULL值和空字符串在写入文件时无法区分,因为两者都是作为空字符串写入的。如果需要在重新读入文件时区分这两者,那么不应该使用固定行格式。

尝试将NULL加载到NOT NULL列会导致为列的数据类型分配隐式默认值,并出现警告,或者在严格的SQL模式下出现错误。

不被load data infile所支持的情况:
.固定大小的行(fields terminated by和fields enclosed by都是空的)和BLOB或TEXT列
.如果指定一个分隔符与另一个分隔符或前缀相同,则LOAD DATA INFILE无法正确解释输入。例如,下面的FIELDS子句会导致问题:FIELDS TERMINATED BY ‘”‘ ENCLOSED BY ‘”‘

如果fields escaped by为空,则包含FIELDS ENCLOSED BY或LINES TERMINATED BY后跟FIELDS TERMINATED BY的字段值将导致LOAD DATA INFILE过早停止读取字段或行。这是因为LOAD DATA INFILE不能正确地确定字段或行值的结束位置。

下面的示例加载persondata表的所有列:

LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;

默认情况下,当LOAD DATA INFILE语句末尾没有提供字段列表时,输入行将包含每个表的所有字段。如果只想加载表的部分列,请指定字段列表:

LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata (col1,col2,...);

如果输入文件中字段的顺序与表中列的顺序不同,还必须指定字段列表。否则,MySQL无法判断如何将输入字段与表列匹配。

列列表可以包含列名或用户变量。对于用户变量,SET子句允许您在将结果分配给列之前对其值执行转换.

SET子句中的用户变量有几种用法。下面的示例将第一个输入列直接用于t1.column1的值,并将第二个输入列赋值给一个用户变量,该变量在用于t1.column2的值之前进行除法操作

LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, @var1)
SET column2 = @var1/100;

SET子句可用于提供非从输入文件派生的值。下面的语句将column3设置为当前日期和时间

LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, column2)
SET column3 = CURRENT_TIMESTAMP;

可以通过指定用户变量且不将变量指定到表列来放弃输入值:

LOAD DATA INFILE 'file.txt'
INTO TABLE t1
(column1, @dummy, column2, @dummy, column3);

列/变量列表和SET子句的使用受以下限制:
.SET子句中的赋值操作符应该只有列名在赋值操作符的左边。
.你可以在SET赋值的右边使用子查询。返回要分配给列的值的子查询只能是标量子查询。此外,也不能使用子查询从正在加载的表中进行选择
.对于列/变量列表或SET子句,不处理被IGNORE子句忽略的行
.当以固定行格式加载数据时,不能使用用户变量,因为用户变量没有显示宽度

在处理输入行时,LOAD DATA将其分割为字段,并根据列/变量列表和SET子句(如果存在的话)使用这些值。然后将生成的行插入到表中。如果表中有BEFORE INSERT或AFTER INSERT触发器,则分别在插入行之前或之后激活它们。

如果一个输入行有太多的字段,额外的字段将被忽略,警告的数量将增加

如果输入行字段太少,则将缺少输入字段的表列设置为默认值。

对空字段值的解释与缺失字段不同:
.对于字符串类型,列被设置为空字符串
.对于数字类型,列被设置为0
.对于日期和时间类型,该列被设置为该类型的适当零值

如果在INSERT或UPDATE语句中显式地将空字符串赋给字符串、数字类型或日期或时间类型,则会得到相同的值

如果SQL模式被设置为限制值,那么空字段值或不正确字段值的处理与刚才描述的不同。例如,如果sql_mode设置为traditional,对于数字列转换空值或值(如’x’)将导致错误,而不是转换为0。(对于LOCAL或IGNORE,即使使用限制性sql_mode值,也会出现警告而不是错误,并且使用与非限制性SQL模式相同的最接近值行为插入行。这是因为服务器没有办法在操作过程中停止文件的传输。)

只有TIMESTAMP列列值为NULL和列没有声明为允许NULL值或者如果TIMESTAMP列的默认值是当前的时间戳,并且在指定字段列表时从字段列表中省略它时,TIMESTAMP列会被设置为当前日期和时间。

LOAD DATA INFILE将所有输入视为字符串,所以不能像INSERT语句那样对ENUM或SET列使用数值。所有的ENUM和SET值必须指定为字符串。BIT值不能使用二进制表示法直接加载(例如,b’011010′)。为了解决这个问题,使用SET子句去掉前导b’和末尾b’,并执行base-2到base-10的转换,以便MySQL正确地将值加载到BIT列中:

[mysql@localhost ~]$ cat /var/lib/mysql/bit_test.txt
b'10'
b'1111111'

mysql> create table bit_test(b bit(10));
Query OK, 0 rows affected (0.10 sec)


mysql> load data infile '/var/lib/mysql/bit_test.txt'
    -> into table bit_test(@var1)
    -> set b=cast(conv(mid(@var1,3,length(@var1)-3),2,10) as unsigned);
Query OK, 2 rows affected (0.15 sec)
Records: 2  Deleted: 0  Skipped: 0  Warnings: 0


mysql> select bin(b+0) from bit_test;
+----------+
| bin(b+0) |
+----------+
| 10       |
| 1111111  |
+----------+
2 rows in set (0.00 sec)

对于0b二进制表示法中的BIT值(例如0b011010),使用这个SET子句来去掉前导的0b:

SET b = CAST(CONV(MID(@var1, 3, LENGTH(@var1)-2), 2, 10) AS UNSIGNED)

在Unix上,如果需要LOAD DATA从管道读取数据,可以使用以下技术(示例将/目录的清单加载到表db1.t1中):

mkfifo /mysql/data/db1/ls.dat
chmod 666 /mysql/data/db1/ls.dat
find / -ls > /mysql/data/db1/ls.dat &
mysql -e "LOAD DATA INFILE 'ls.dat' INTO TABLE t1" db1

在这里,您必须在单独的终端上运行生成要加载的数据的命令和mysql命令,或者在后台运行数据生成过程(如前面的示例所示)。如果您不这样做,管道将阻塞,直到数据被mysql进程读取。

当LOAD DATA INFILE语句完成时,它将返回如下格式的信息字符串

Records: 1 Deleted: 0 Skipped: 0 Warnings: 0

Windows 使用VSCode远程连接到Linux开发调试MySQL

Windows 使用VSCode远程连接到Linux开发调试MySQL

1.Linux系统上安装相关开发工具

[root@gbase yum.repos.d]# yum install gdb-gdbserver

[root@gbase yum.repos.d]# yum install gdb

[root@gbase yum.repos.d]# yum install gcc

[root@gbase yum.repos.d]# yum install cmake

2.配置VSCode可以免密登录Linux

2.1在Windows上生成密钥

C:\Users\Administrator>ssh-keygen -t rsa

Generating public/private rsa key pair.

Enter file in which to save the key (C:\Users\Administrator\.ssh\id_rsa):

Enter passphrase (empty for no passphrase):

Enter same passphrase again:

Your identification has been saved in id_rsa.

Your public key has been saved in id_ras.pub.

The key fingerprint is:

SHA256:2ya72QX0JQBxKTLM+3S1H3FFYnHHrve1t0cSbqXJiqI mysql@gbase

The key’s randomart image is:

+—[RSA 2048]—-+

| o ooo. ++*|

| = …….o+|

| + ……+ |

| . …..oo o|

| oS.. .+ B |

| .o . X +|

| o o..o ++|

| .*… .+|

| E.+o. .+|

+—-[SHA256]—–+

2.2 在Linux服务器上生成密钥

[root@gbase ~]# su – mysql

Last login: Sun Sep 26 09:24:11 CST 2021 on pts/5

[mysql@gbase ~]$ pwd

/home/mysql

[mysql@gbase ~]$ ls -lrt

total 0

drwxrwxr-x. 2 mysql mysql 6 Sep 24 16:19 perl5

[mysql@gbase ~]$ cd ~/.ssh

-bash: cd: /home/mysql/.ssh: No such file or directory

[mysql@gbase ~]$ mkdir ~/.ssh

[mysql@gbase ~]$ cd ~/.ssh

[mysql@gbase .ssh]$ pwd

/home/mysql/.ssh

[mysql@gbase .ssh]$ ls -lrt

total 0

增加root权限:visudo 进入文本后找到root ALL=(ALL) ALL,另起一行,加入admin ALL=(ALL) NOPASSWD:ALL su admin 切换到新用户 再使

用sudo su -切换回root,说明权限正常,进行下一步

[root@gbase ~]# visudo

## Allow root to run any commands anywhere

root ALL=(ALL) ALL

mysql ALL=(ALL) NOPASSWD:ALL

[mysql@gbase ~]$ sudo su –

Last login: Sun Sep 26 11:41:38 CST 2021 on pts/1

[root@gbase ~]# su – mysql

Last login: Sun Sep 26 14:20:50 CST 2021 from 192.168.1.12 on pts/3

[mysql@gbase ~]$

2.3将windows中生成的公钥上传到/home/mysql/.ssh/目录

C:\Users\Administrator>scp C:\Users\Administrator\.ssh\id_rsa.pud mysql@192.168.1.249:/home/mysql/.ssh/authorized_keys

[mysql@gbase ~]$ chmod 700 /home/mysql/.ssh

[mysql@gbase ~]$ chmod 600 /home/mysql/.ssh/authorized_keys

2.4切换到root,关闭root登录 sudo su – vim /etc/ssh/sshd_config 找到#PermitRootLogin yes去掉#把yes改为no systemctl restart sshd 重启服务并生效

[root@gbase .ssh]# vim /etc/ssh/sshd_config

# $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $

# This is the sshd server system-wide configuration file. See

# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/local/bin:/usr/bin

# The strategy used for options in the default sshd_config shipped with

# OpenSSH is to specify options with their default value where

# possible, but leave them commented. Uncommented options override the

# default value.

# If you want to change the port on a SELinux system, you have to tell

# SELinux about this change.

# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER

#

Port 22

#AddressFamily any

#ListenAddress 0.0.0.0

#ListenAddress ::

HostKey /etc/ssh/ssh_host_rsa_key

#HostKey /etc/ssh/ssh_host_dsa_key

HostKey /etc/ssh/ssh_host_ecdsa_key

HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying

#RekeyLimit default none

# Logging

#SyslogFacility AUTH

SyslogFacility AUTHPRIV

#LogLevel INFO

# Authentication:

#LoginGraceTime 2m

PermitRootLogin no #改成no

#StrictModes yes

#MaxAuthTries 6

#MaxSessions 10

RSAAuthentication yes #要开启

PubkeyAuthentication yes #要开启

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2

# but this is overridden so installations will only check .ssh/authorized_keys

AuthorizedKeysFile .ssh/authorized_keys

[root@gbase ~]# service sshd restart

Redirecting to /bin/systemctl restart sshd.service

在windows中测试ssh登录

C:\Users\Administrator>ssh mysql@192.168.1.249

Last login: Sun Sep 26 14:22:54 2021

]ysql@gbase:~[mysql@gbase ~]$ pwd

/home/mysql

2.5 配置vscode通过remote ssh连接Linux的配置文件C:\Users\Administrator\.ssh\config

Host 192.168.1.249

HostName 192.168.1.249

User root

IdentityFile “D:\ssh\vscode”

2.6 通过vscode远程连接Linux服务器出现以下错误

> Waiting for client to transfer server archive…

> Waiting for /home/mysql/.vscode-server/bin/7f6ab5485bbc008386c4386d08766667e1552

> 44e/vscode-scp-done.flag and vscode-server.tar.gz to exist

>

[12:31:20.267] Got request to download on client for {“platform”:”linux”,”arch”:”x64″,”destFolder”:”/home/mysql/.vscode-server/bin/7f6ab5485bbc008386c4386d08766667e155244e”}

[12:31:20.268] Downloading VS Code server locally…

[12:31:20.420] Resolver error: Error: Running the contributed command: ‘_workbench.downloadResource’ failed.

[mysql@gbase /]$ cd /home/mysql

[mysql@gbase ~]$ ls -lrt .vscode-server

total 0

drwxrwxr-x. 3 mysql mysql 54 Sep 26 09:46 bin

[mysql@gbase ~]$ cd .vscode-server

[mysql@gbase .vscode-server]$ ls

bin

[mysql@gbase .vscode-server]$ cd bin

[mysql@gbase bin]$ ls

7f6ab5485bbc008386c4386d08766667e155244e

[mysql@gbase bin]$ cd 7f6ab5485bbc008386c4386d08766667e155244e/

[mysql@gbase 7f6ab5485bbc008386c4386d08766667e155244e]$ ls

vscode-remote-lock.mysql.7f6ab5485bbc008386c4386d08766667e155244e vscode-server.tar.gz

[mysql@gbase 7f6ab5485bbc008386c4386d08766667e155244e]$ ls -lrt

total 0

-rw-rw-r–. 1 mysql mysql 0 Sep 26 11:37 vscode-remote-lock.mysql.7f6ab5485bbc008386c4386d08766667e155244e

-rw-rw-r–. 1 mysql mysql 0 Sep 26 11:37 vscode-server.tar.gz

上面的7f开头的文件夹称为Commit Id,现在利用Commit ID下载远程连接需要的文件。对于Stabe Version(在VS Code报错的的窗口中Ctrl+F

搜索stable,有则为Stable Version)的Remote SSH插件,如下图,在“输出”窗口中Ctrl+F搜索“stable”。

[12:31:14.904] Using commit id “7f6ab5485bbc008386c4386d08766667e155244e” and quality “stable” for server

然后使用这个链接:https://update.code.visualstudio.com/commit:$COMMIT_ID/server-linux-x64/stable下载所需文件,注意链接中的

$COMMIT_ID这几个字符(注意$不要忘记)需要换成自己的,比如我的是 7f6ab5485bbc008386c4386d08766667e155244e,那么此时我通

过https://update.code.visualstudio.com/commit:7f6ab5485bbc008386c4386d08766667e155244e/server-linux-x64/stable就可以下载到

我需要的文件。

对于Insider版本,

通过https://update.code.visualstudio.com/commit:7f6ab5485bbc008386c4386d08766667e155244e/server-linux-x64/insider这个链接下载相

应文件。

下载完毕后,将下载的文件upload到Remote Server的~/.vscode-server/bin/xxx文件夹下(也可以在Remote Server上直接

执行wget https://vscode.cdn.azure.cn/stable/7f6ab5485bbc008386c4386d08766667e155244e/vscode-server-linux-x64.tar.gz即可下载,

这样就不用进行上传操作了),同时删除其他文件,最后再使用tar -xvf vscode-server-linux-x64.tar.gz –strip-components 1解压文件,

sftp> put D:\ssh\vscode-server-linux-x64.tar.gz

Uploading vscode-server-linux-x64.tar.gz to /home/mysql/vscode-server-linux-x64.tar.gz

100% 45296KB 45296KB/s 00:00:00

D:/ssh/vscode-server-linux-x64.tar.gz: 46383314 bytes transferred in 0 seconds (45296 KB/s)

[mysql@gbase 7f6ab5485bbc008386c4386d08766667e155244e]$ tar -xvf vscode-server-linux-x64.tar.gz –strip-components 1

然后使用chmod +x node server.sh为node和server.sh添加可执行权限。

[mysql@gbase 7f6ab5485bbc008386c4386d08766667e155244e]$ chmod +x node server.sh

[mysql@gbase 7f6ab5485bbc008386c4386d08766667e155244e]$ ls -lrt

total 117512

-rwxr-xr-x. 1 mysql mysql 222 Sep 22 20:00 server.sh

-rw-r–r–. 1 mysql mysql 34147 Sep 22 20:00 product.json

-rw-r–r–. 1 mysql mysql 1255 Sep 22 20:00 package.json

-rw-r–r–. 1 mysql mysql 13380 Sep 22 20:00 LICENSE

-rwxr-xr-x. 1 mysql mysql 73873984 Sep 22 20:02 node

drwxr-xr-x. 3 mysql mysql 135 Sep 22 20:02 out

drwxr-xr-x. 3 mysql mysql 33 Sep 22 20:02 bin

drwxr-xr-x. 32 mysql mysql 4096 Sep 22 20:02 extensions

drwxr-xr-x. 78 mysql mysql 4096 Sep 22 20:02 node_modules

-rw-rw-r–. 1 mysql mysql 0 Sep 26 11:37 vscode-remote-lock.mysql.7f6ab5485bbc008386c4386d08766667e155244e

-rw-rw-r–. 1 mysql mysql 0 Sep 26 11:37 vscode-server.tar.gz

-rw-rw-r–. 1 mysql mysql 46383314 Sep 26 11:57 vscode-server-linux-x64.tar.gz

再次使用VS Code尝试链接,这一步会链接成功。

3.vscode在远程远程服务器上依次安装 C/C++、CMake、CMake Tools插件

在使用vscode 远程调试程序时出现以下信息:

Updating C/C++ dependencies…

Downloading package ‘C/C++ language components (Linux / x86_64)’ Failed. Retrying… Failed. Retrying… Failed. Retrying…Waiting 8 seconds… Failed. Retrying…Waiting 15 seconds… Failed. Retrying…Waiting 15 seconds… Failed. Retrying…Waiting 15 seconds… Failed. Retrying…Waiting 15 seconds… Failed. Retrying…Waiting 15 seconds… Failed. Retrying…Waiting 15 seconds… Failed to download https://go.microsoft.com/fwlink/?linkid=2170969

Failed at stage: downloadPackages

Error: getaddrinfo ENOTFOUND go.microsoft.com

at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:67:26)

If you work in an offline environment or repeatedly see this error, try downloading a version of the extension with all the dependencies pre-included from https://github.com/microsoft/vscode-cpptools/releases, then use the “Install from VSIX” command in VS Code to install it.


安装 C/C++ language components插件失败

我们只能手动安装

打开网址https://go.microsoft.com/fwlink/?linkid=2170969下载bin_linupwd

x.zip文件

将bin_linux.zip文件解压

cpptools

cpptools-srv

LICENSE.txt

将这三个文件拷贝到远程Linux服务器的/home/mysql/.vscode-server/extensions/ms-vscode.cpptools-1.6.0/bin目录中

如果原先存在这个文件的话先将其备份。

sftp> put F:\bin_linux\bin\*

Uploading cpptools to /home/mysql/.vscode-server/extensions/ms-vscode.cpptools-1.6.0/bin/cpptools

100% 19544KB 19544KB/s 00:00:00

F:/bin_linux/bin/cpptools: 20014008 bytes transferred in 0 seconds (19544 KB/s)

Uploading cpptools-srv to /home/mysql/.vscode-server/extensions/ms-vscode.cpptools-1.6.0/bin/cpptools-srv

100% 11508KB 11508KB/s 00:00:00

F:/bin_linux/bin/cpptools-srv: 11784664 bytes transferred in 0 seconds (11508 KB/s)

Uploading LICENSE.txt to /home/mysql/.vscode-server/extensions/ms-vscode.cpptools-1.6.0/bin/LICENSE.txt

100% 11KB 11KB/s 00:00:00

F:/bin_linux/bin/LICENSE.txt: 11972 bytes transferred in 0 seconds (11 KB/s)

但是没有用,仍然报错

如是通过vsix来进行安装

github上release好多个版本,我远程看代码的主机是redhat Linux系统,所有下载cpptools-linux.vsix。

先删除我们上传到/home/mysql/.vscode-server/extensions/ms-vscode.cpptools-1.6.0/bin的三个文件

[mysql@gbase bin]$ ls -lrt

total 31188

-rw-rw-r–. 1 mysql mysql 11784664 Aug 23 22:29 cpptools-srv

-rw-rw-r–. 1 mysql mysql 20014008 Aug 23 22:29 cpptools

-rw-rw-r–. 1 mysql mysql 11972 Aug 23 22:34 LICENSE.txt

-rw-rw-r–. 1 mysql mysql 582 Sep 26 12:05 common.json

-rw-rw-r–. 1 mysql mysql 301 Sep 26 12:05 linux.clang.arm.json

-rw-rw-r–. 1 mysql mysql 310 Sep 26 12:05 linux.clang.arm64.json

-rw-rw-r–. 1 mysql mysql 300 Sep 26 12:05 linux.clang.x64.json

-rw-rw-r–. 1 mysql mysql 291 Sep 26 12:05 linux.clang.x86.json

-rw-rw-r–. 1 mysql mysql 301 Sep 26 12:05 linux.gcc.arm.json

-rw-rw-r–. 1 mysql mysql 310 Sep 26 12:05 linux.gcc.arm64.json

-rw-rw-r–. 1 mysql mysql 302 Sep 26 12:05 linux.gcc.x64.json

-rw-rw-r–. 1 mysql mysql 291 Sep 26 12:05 linux.gcc.x86.json

-rw-rw-r–. 1 mysql mysql 284 Sep 26 12:05 macos.clang.arm.json

-rw-rw-r–. 1 mysql mysql 293 Sep 26 12:05 macos.clang.arm64.json

-rw-rw-r–. 1 mysql mysql 283 Sep 26 12:05 macos.clang.x64.json

-rw-rw-r–. 1 mysql mysql 274 Sep 26 12:05 macos.clang.x86.json

-rw-rw-r–. 1 mysql mysql 284 Sep 26 12:05 macos.gcc.arm.json

-rw-rw-r–. 1 mysql mysql 293 Sep 26 12:05 macos.gcc.arm64.json

-rw-rw-r–. 1 mysql mysql 283 Sep 26 12:05 macos.gcc.x64.json

-rw-rw-r–. 1 mysql mysql 274 Sep 26 12:05 macos.gcc.x86.json

drwxrwxr-x. 15 mysql mysql 145 Sep 26 12:05 messages

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.clang.arm.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.clang.arm64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.clang.x64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.clang.x86.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.gcc.arm.json

-rw-rw-r–. 1 mysql mysql 89 Sep 26 12:05 windows.gcc.arm64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.gcc.x64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.gcc.x86.json

-rw-rw-r–. 1 mysql mysql 299 Sep 26 12:05 windows.msvc.arm.json

-rw-rw-r–. 1 mysql mysql 324 Sep 26 12:05 windows.msvc.arm64.json

-rw-rw-r–. 1 mysql mysql 383 Sep 26 12:05 windows.msvc.x64.json

-rw-rw-r–. 1 mysql mysql 359 Sep 26 12:05 windows.msvc.x86.json

[mysql@gbase bin]$ rm -rf cpptools*

[mysql@gbase bin]$ rm -rf LICENSE.txt

[mysql@gbase bin]$ ls -lrt

total 116

-rw-rw-r–. 1 mysql mysql 582 Sep 26 12:05 common.json

-rw-rw-r–. 1 mysql mysql 301 Sep 26 12:05 linux.clang.arm.json

-rw-rw-r–. 1 mysql mysql 310 Sep 26 12:05 linux.clang.arm64.json

-rw-rw-r–. 1 mysql mysql 300 Sep 26 12:05 linux.clang.x64.json

-rw-rw-r–. 1 mysql mysql 291 Sep 26 12:05 linux.clang.x86.json

-rw-rw-r–. 1 mysql mysql 301 Sep 26 12:05 linux.gcc.arm.json

-rw-rw-r–. 1 mysql mysql 310 Sep 26 12:05 linux.gcc.arm64.json

-rw-rw-r–. 1 mysql mysql 302 Sep 26 12:05 linux.gcc.x64.json

-rw-rw-r–. 1 mysql mysql 291 Sep 26 12:05 linux.gcc.x86.json

-rw-rw-r–. 1 mysql mysql 284 Sep 26 12:05 macos.clang.arm.json

-rw-rw-r–. 1 mysql mysql 293 Sep 26 12:05 macos.clang.arm64.json

-rw-rw-r–. 1 mysql mysql 283 Sep 26 12:05 macos.clang.x64.json

-rw-rw-r–. 1 mysql mysql 274 Sep 26 12:05 macos.clang.x86.json

-rw-rw-r–. 1 mysql mysql 284 Sep 26 12:05 macos.gcc.arm.json

-rw-rw-r–. 1 mysql mysql 293 Sep 26 12:05 macos.gcc.arm64.json

-rw-rw-r–. 1 mysql mysql 283 Sep 26 12:05 macos.gcc.x64.json

-rw-rw-r–. 1 mysql mysql 274 Sep 26 12:05 macos.gcc.x86.json

drwxrwxr-x. 15 mysql mysql 145 Sep 26 12:05 messages

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.clang.arm.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.clang.arm64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.clang.x64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.clang.x86.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.gcc.arm.json

-rw-rw-r–. 1 mysql mysql 89 Sep 26 12:05 windows.gcc.arm64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.gcc.x64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 12:05 windows.gcc.x86.json

-rw-rw-r–. 1 mysql mysql 299 Sep 26 12:05 windows.msvc.arm.json

-rw-rw-r–. 1 mysql mysql 324 Sep 26 12:05 windows.msvc.arm64.json

-rw-rw-r–. 1 mysql mysql 383 Sep 26 12:05 windows.msvc.x64.json

-rw-rw-r–. 1 mysql mysql 359 Sep 26 12:05 windows.msvc.x86.json

通过vscode 从vsix来进行安装,选择本地目录D:\ssh\cpptools-linux.vsix文件

[mysql@gbase bin]$ ls -lrt

total 31188

-rw-rw-r–. 1 mysql mysql 582 Sep 26 15:01 common.json

-rw-rw-r–. 1 mysql mysql 20014008 Sep 26 15:01 cpptools

-rw-rw-r–. 1 mysql mysql 11784664 Sep 26 15:01 cpptools-srv

-rw-rw-r–. 1 mysql mysql 11972 Sep 26 15:01 LICENSE.txt

-rw-rw-r–. 1 mysql mysql 301 Sep 26 15:01 linux.clang.arm.json

-rw-rw-r–. 1 mysql mysql 310 Sep 26 15:01 linux.clang.arm64.json

-rw-rw-r–. 1 mysql mysql 300 Sep 26 15:01 linux.clang.x64.json

-rw-rw-r–. 1 mysql mysql 291 Sep 26 15:01 linux.clang.x86.json

-rw-rw-r–. 1 mysql mysql 301 Sep 26 15:01 linux.gcc.arm.json

-rw-rw-r–. 1 mysql mysql 310 Sep 26 15:01 linux.gcc.arm64.json

-rw-rw-r–. 1 mysql mysql 302 Sep 26 15:01 linux.gcc.x64.json

-rw-rw-r–. 1 mysql mysql 291 Sep 26 15:01 linux.gcc.x86.json

-rw-rw-r–. 1 mysql mysql 284 Sep 26 15:01 macos.clang.arm.json

-rw-rw-r–. 1 mysql mysql 293 Sep 26 15:01 macos.clang.arm64.json

-rw-rw-r–. 1 mysql mysql 283 Sep 26 15:01 macos.clang.x64.json

-rw-rw-r–. 1 mysql mysql 274 Sep 26 15:01 macos.clang.x86.json

-rw-rw-r–. 1 mysql mysql 284 Sep 26 15:01 macos.gcc.arm.json

-rw-rw-r–. 1 mysql mysql 293 Sep 26 15:01 macos.gcc.arm64.json

-rw-rw-r–. 1 mysql mysql 283 Sep 26 15:01 macos.gcc.x64.json

-rw-rw-r–. 1 mysql mysql 274 Sep 26 15:01 macos.gcc.x86.json

drwxrwxr-x. 15 mysql mysql 145 Sep 26 15:01 messages

-rw-rw-r–. 1 mysql mysql 87 Sep 26 15:01 windows.clang.arm.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 15:01 windows.clang.arm64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 15:01 windows.clang.x64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 15:01 windows.clang.x86.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 15:01 windows.gcc.arm.json

-rw-rw-r–. 1 mysql mysql 89 Sep 26 15:01 windows.gcc.arm64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 15:01 windows.gcc.x64.json

-rw-rw-r–. 1 mysql mysql 87 Sep 26 15:01 windows.gcc.x86.json

-rw-rw-r–. 1 mysql mysql 299 Sep 26 15:01 windows.msvc.arm.json

-rw-rw-r–. 1 mysql mysql 324 Sep 26 15:01 windows.msvc.arm64.json

-rw-rw-r–. 1 mysql mysql 383 Sep 26 15:01 windows.msvc.x64.json

-rw-rw-r–. 1 mysql mysql 359 Sep 26 15:01 windows.msvc.x86.json

重启vscdoe

4.使用vscode远程编译Linux服务器的MySQL源码,mysql源码在/soft/mysql-5.7.26/目录

这里需要配置Cmake 生成setting.json配置文件 点击CMake Tool的设置按钮,再点击Extention Settings

这里选择Remote [SSH:192.168.1.249],我这对于Build Directory选择使用默认配置,因为${workspaceFolder}就是/soft/mysql-5.7.26目录,所以$${workspaceFolder}/build也就是/soft/mysql-5.7.26/build目录

所以Source Directory目录选择使用默认的$workspaceFolder}目录

给Configure Args配置以下三个参数

-DWITH_BOOST=/soft/mysql-5.7.26/boost/boost_1_59_0

-DDOWNLOAD_BOOST=1

-DWITH_DEBUG=1

选择编译器

给CMake选择Debug模式

然后进行编译

编译完成后,在Linux服务器上初始化mysql数据库

创建data,etc目录用来分别存放数据文件与配置文件my.cnf

[mysql@gbase build]$ mkdir {data,etc}

[mysql@gbase build]$ cd etc

[mysql@gbase etc]$ vi my.cnf

[mysqld]

basedir=/soft/mysql-5.7.26/build

datadir=/soft/mysql-5.7.26/build/data

bind-address=0.0.0.0

user=mysql

port=3306

log-error=/soft/mysql-5.7.26/build/data/mysql.err

pid-file=/soft/mysql-5.7.26/build/data/mysqld.pid

socket = /soft/mysql-5.7.26/build/data/mysql.sock

character-set-server=utf8mb4

default-storage-engine=INNODB

explicit_defaults_for_timestamp = true

[mysql@gbase build]$ sql/mysqld –defaults-file=etc/my.cnf –initialize-insecure

[mysql@gbase build]$ cd data

[mysql@gbase data]$ ls

auto.cnf ib_buffer_pool ibdata1 ib_logfile0 ib_logfile1 mysql mysql.err performance_schema sys

[mysql@gbase data]$ ls -lrt

total 110632

-rw-r—–. 1 mysql mysql 50331648 Sep 26 15:43 ib_logfile1

-rw-r—–. 1 mysql mysql 56 Sep 26 15:43 auto.cnf

-rw-r—–. 1 mysql mysql 1046 Sep 26 15:43 mysql.err

drwxr-x—. 2 mysql mysql 8192 Sep 26 15:43 performance_schema

drwxr-x—. 2 mysql mysql 4096 Sep 26 15:43 mysql

drwxr-x—. 2 mysql mysql 8192 Sep 26 15:43 sys

-rw-r—–. 1 mysql mysql 419 Sep 26 15:43 ib_buffer_pool

-rw-r—–. 1 mysql mysql 50331648 Sep 26 15:43 ib_logfile0

-rw-r—–. 1 mysql mysql 12582912 Sep 26 15:43 ibdata1

[mysql@gbase data]$ more mysql.err

2021-09-26T07:43:43.288066Z 0 [Warning] Changed limits: max_open_files: 1024 (requested 5000)

2021-09-26T07:43:43.288312Z 0 [Warning] Changed limits: table_open_cache: 431 (requested 2000)

2021-09-26T07:43:43.289227Z 0 [ERROR] Can’t find error-message file ‘/soft/mysql-5.7.26/build/share/errmsg.sys’. Check error-message file location and ‘lc-messages-dir’ configuration directive.

2021-09-26T07:43:46.058883Z 0 [Warning] InnoDB: New log files created, LSN=45790

2021-09-26T07:43:46.360628Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.

2021-09-26T07:43:46.558161Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 7b190ba6-1e9d-11ec-93d5-005056a31fca.

2021-09-26T07:43:46.567453Z 0 [Warning] Gtid table is not ready to be used. Table ‘mysql.gtid_executed’ cannot be opened.

2021-09-26T07:43:46.569018Z 1 [Warning] root@localhost is created with an empty password ! Please consider switching off the –initialize-insecure option.

[mysql@gbase mysql-5.7.26]$ gcc -v -E -x c++ –

Using built-in specs.

COLLECT_GCC=gcc

Target: x86_64-redhat-linux

Configured with: ../configure –prefix=/usr –mandir=/usr/share/man –infodir=/usr/share/info –with-bugurl=http://bugzilla.redhat.com/bugzilla –enable-bootstrap –enable-shared –enable-threads=posix –enable-checking=release –with-system-zlib –enable-__cxa_atexit –disable-libunwind-exceptions –enable-gnu-unique-object –enable-linker-build-id –with-linker-hash-style=gnu –enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto –enable-plugin –enable-initfini-array –disable-libgcj –with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install –with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install –enable-gnu-indirect-function –with-tune=generic –with-arch_32=x86-64 –build=x86_64-redhat-linux

Thread model: posix

gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)

COLLECT_GCC_OPTIONS=’-v’ ‘-E’ ‘-mtune=generic’ ‘-march=x86-64’

/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/cc1plus -E -quiet -v -D_GNU_SOURCE – -mtune=generic -march=x86-64

ignoring nonexistent directory “/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include-fixed”

ignoring nonexistent directory “/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../x86_64-redhat-linux/include”

#include “…” search starts here:

#include < ...> search starts here:

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/x86_64-redhat-linux

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/backward

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include

/usr/local/include

/usr/include

将下面的内容加入到c_cpp_properties.json中的includePath中

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/x86_64-redhat-linux

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/../../../../include/c++/4.8.5/backward

/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include

/usr/local/include

/usr/include

加入后错误信息消失

windows系统vscode远程调试MySQL

这里介绍如何使用windows上的 vscode远程访问Linux的mysql源码来执行远程调试MySQL

1.在本地windows安装openssh

下载安装包OpenSSH-Win64.zip并解压

进行解压后的目录F:\OpenSSH-Win64\OpenSSH

在cmd命令窗口中执行下面命令进行安装

powershell.exe -ExecutionPolicy Bypass -File install-sshd.ps1

开放22号端口(如果你在windows关闭了防火墙并配置了入站规则可以不执行如下命令,多执行不影响)

netsh advfirewall firewall add rule name=sshd dir=in action=allow protocol=TCP localport=22

配置开机自启sshd服务

sc config sshd start= auto

将F:\OpenSSH-Win64\OpenSSH添加到环境变量path中,免得每次都要切到F:\OpenSSH-Win64\OpenSSH才能使用ssh,启动ssh服务

net start sshd

2.1在Windows上生成密钥

C:\Users\Administrator>ssh-keygen -t rsa

Generating public/private rsa key pair.

Enter file in which to save the key (C:\Users\Administrator\.ssh\id_rsa):

Enter passphrase (empty for no passphrase):

Enter same passphrase again:

Your identification has been saved in id_rsa.

Your public key has been saved in id_ras.pub.

The key fingerprint is:

SHA256:2ya72QX0JQBxKTLM+3S1H3FFYnHHrve1t0cSbqXJiqI mysql@gbase

The key’s randomart image is:

+—[RSA 2048]—-+

| o ooo. ++*|

| = …….o+|

| + ……+ |

| . …..oo o|

| oS.. .+ B |

| .o . X +|

| o o..o ++|

| .*… .+|

| E.+o. .+|

+—-[SHA256]—–+

2.2 在Linux服务器上生成密钥

[root@gbase ~]# su – mysql

Last login: Sun Sep 26 09:24:11 CST 2021 on pts/5

[mysql@gbase ~]$ pwd

/home/mysql

[mysql@gbase ~]$ ls -lrt

total 0

drwxrwxr-x. 2 mysql mysql 6 Sep 24 16:19 perl5

[mysql@gbase ~]$ cd ~/.ssh

-bash: cd: /home/mysql/.ssh: No such file or directory

[mysql@gbase ~]$ mkdir ~/.ssh

[mysql@gbase ~]$ cd ~/.ssh

[mysql@gbase .ssh]$ pwd

/home/mysql/.ssh

[mysql@gbase .ssh]$ ls -lrt

total 0

增加root权限:visudo 进入文本后找到root ALL=(ALL) ALL,另起一行,加入admin ALL=(ALL) NOPASSWD:ALL su admin 切换到新用户 再使

用sudo su -切换回root,说明权限正常,进行下一步

[root@gbase ~]# visudo

## Allow root to run any commands anywhere

root ALL=(ALL) ALL

mysql ALL=(ALL) NOPASSWD:ALL

[mysql@gbase ~]$ sudo su –

Last login: Sun Sep 26 11:41:38 CST 2021 on pts/1

[root@gbase ~]# su – mysql

Last login: Sun Sep 26 14:20:50 CST 2021 from 192.168.1.12 on pts/3

[mysql@gbase ~]$

2.3将windows中生成的公钥上传到/home/mysql/.ssh/目录

C:\Users\Administrator>scp C:\Users\Administrator\.ssh\id_rsa.pud mysql@192.168.1.249:/home/mysql/.ssh/authorized_keys

[mysql@gbase ~]$ chmod 700 /home/mysql/.ssh

[mysql@gbase ~]$ chmod 600 /home/mysql/.ssh/authorized_keys

2.4切换到root,关闭root登录 sudo su – vim /etc/ssh/sshd_config 找到#PermitRootLogin yes去掉#把yes改为no systemctl restart sshd 重启服务并生效

[root@gbase .ssh]# vim /etc/ssh/sshd_config

# $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $

# This is the sshd server system-wide configuration file. See

# sshd_config(5) for more information.

# This sshd was compiled with PATH=/usr/local/bin:/usr/bin

# The strategy used for options in the default sshd_config shipped with

# OpenSSH is to specify options with their default value where

# possible, but leave them commented. Uncommented options override the

# default value.

# If you want to change the port on a SELinux system, you have to tell

# SELinux about this change.

# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER

#

Port 22

#AddressFamily any

#ListenAddress 0.0.0.0

#ListenAddress ::

HostKey /etc/ssh/ssh_host_rsa_key

#HostKey /etc/ssh/ssh_host_dsa_key

HostKey /etc/ssh/ssh_host_ecdsa_key

HostKey /etc/ssh/ssh_host_ed25519_key

# Ciphers and keying

#RekeyLimit default none

# Logging

#SyslogFacility AUTH

SyslogFacility AUTHPRIV

#LogLevel INFO

# Authentication:

#LoginGraceTime 2m

PermitRootLogin no #改成no

#StrictModes yes

#MaxAuthTries 6

#MaxSessions 10

RSAAuthentication yes #要开启

PubkeyAuthentication yes #要开启

# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2

# but this is overridden so installations will only check .ssh/authorized_keys

AuthorizedKeysFile .ssh/authorized_keys

[root@gbase ~]# service sshd restart

Redirecting to /bin/systemctl restart sshd.service

在windows中测试ssh登录

C:\Users\Administrator>ssh mysql@192.168.1.249

Last login: Sun Sep 26 14:22:54 2021

]ysql@gbase:~[mysql@gbase ~]$ pwd

/home/mysql

给vscode安装remote-development插件

在Linux服务器上编译安装mysql(注意编译时需要开启-DWITH_DEBUG=1)并且启动实例

1.Linux系统上安装相关开发工具

[root@gbase yum.repos.d]# yum install gdb-gdbserver

[root@gbase yum.repos.d]# yum install gdb

[root@localhost ~]# yum -y install gcc* gcc-c++ ncurses* ncurses-devel* cmake* bison* libgcrypt* perl* make*

mysql源码存放在/soft/mysql-5.7.26目录

创建相关目录,build用于编译,build/data用来存储数据库文件,build/etc用来存储my.cnf配置文件

[mysql@gbase mysql-5.7.26]$ mkdir -p build/{data,etc}

[mysql@gbase mysql-5.7.26]$ cd build

[mysql@gbase build]$ ls -lrt

total 0

drwxrwxr-x. 2 mysql mysql 6 Sep 27 07:40 data

drwxrwxr-x. 2 mysql mysql 6 Sep 27 07:40 etc

预编译MySQL

[mysql@gbase mysql-5.7.26]$ cmake . -DCMAKE_INSTALL_PREFIX=/soft/mysql-5.7.26/build -DMYSQL_DATADIR=/soft/mysql-5.7.26/build/data -DMYSQL_UNIX_ADDR=/soft/mysql-5.7.26/build/mysql.sock -DWITH_BOOST=/soft/mysql-5.7.26/boost/boost_1_59_0 -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_PARTITION_STORAGE_ENGINE=1 -DWITH_FEDERATED_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITH_MYISAM_STORAGE_ENGINE=1 -DENABLED_LOCAL_INFILE=1 -DENABLE_DTRACE=0 -DDEFAULT_CHARSET=utf8mb4 -DDEFAULT_COLLATION=utf8mb4_general_ci -DWITH_EMBEDDED_SERVER=1 -DWITH_DEBUG=1

编译源码,这时使用-j 8选项来使用8个进程同时进行编译

[mysql@gbase mysql-5.7.26]$ make -j 8

Building CXX object sql/CMakeFiles/sql.dir/auth/sha2_password_common.cc.o

[100%] Building CXX object sql/CMakeFiles/sql.dir/mysqld_daemon.cc.o

[100%] Generating ../archive_output_directory/mysqlserver_depends.c

Scanning dependencies of target mysqlserver

[100%] Building C object libmysqld/CMakeFiles/mysqlserver.dir/__/archive_output_directory/mysqlserver_depends.c.o

Linking C static library ../archive_output_directory/libmysqld.a

Merging library mysqlserver

Linking CXX static library ../archive_output_directory/libsql.a

[100%] Built target sql

Scanning dependencies of target pfs_connect_attr-t

Scanning dependencies of target mysqld

[100%] Building CXX object sql/CMakeFiles/mysqld.dir/main.cc.o

Linking CXX executable mysqld

[100%] [100%] [100%] Building CXX object storage/perfschema/unittest/CMakeFiles/pfs_connect_attr-t.dir/__/__/__/sql/sql_builtin.cc.o

Building CXX object storage/perfschema/unittest/CMakeFiles/pfs_connect_attr-t.dir/pfs_connect_attr-t.cc.o

Building C object storage/perfschema/unittest/CMakeFiles/pfs_connect_attr-t.dir/__/__/__/mysys/string.c.o

Linking CXX executable pfs_connect_attr-t

[100%] Built target mysqlserver

Scanning dependencies of target mysqltest_embedded

Scanning dependencies of target mysql_embedded

Scanning dependencies of target mysql_client_test_embedded

[100%] [100%] [100%] [100%] Building CXX object libmysqld/examples/CMakeFiles/mysqltest_embedded.dir/__/__/client/mysqltest.cc.o

Building CXX object libmysqld/examples/CMakeFiles/mysql_embedded.dir/__/__/client/completion_hash.cc.o

Building CXX object libmysqld/examples/CMakeFiles/mysql_embedded.dir/__/__/client/mysql.cc.o

[100%] Building CXX object libmysqld/examples/CMakeFiles/mysql_embedded.dir/__/__/client/readline.cc.o

Building C object libmysqld/examples/CMakeFiles/mysql_client_test_embedded.dir/__/__/testclients/mysql_client_test.c.o

Linking CXX executable mysql_embedded

Linking CXX executable mysqltest_embedded

Linking CXX executable mysql_client_test_embedded

[100%] Built target mysqltest_embedded

[100%] Built target mysql_embedded

[100%] Built target mysqld

[100%] Built target pfs_connect_attr-t

[100%] Built target mysql_client_test_embedded

安装

[mysql@gbase mysql-5.7.26]$ make install

— Installing: /soft/mysql-5.7.26/build/mysql-test/./t/xa_prepared_binlog_off.test

— Installing: /soft/mysql-5.7.26/build/mysql-test/./t/xml.test

— Installing: /soft/mysql-5.7.26/build/mysql-test/./valgrind.supp

— Installing: /soft/mysql-5.7.26/build/mysql-test/./mtr

— Installing: /soft/mysql-5.7.26/build/mysql-test/./mysql-test-run

— Installing: /soft/mysql-5.7.26/build/mysql-test/./Makefile

— Installing: /soft/mysql-5.7.26/build/mysql-test/./cmake_install.cmake

— Installing: /soft/mysql-5.7.26/build/mysql-test/./CTestTestfile.cmake

— Installing: /soft/mysql-5.7.26/build/./COPYING-test

— Installing: /soft/mysql-5.7.26/build/./README-test

— Up-to-date: /soft/mysql-5.7.26/build/mysql-test/mtr

— Up-to-date: /soft/mysql-5.7.26/build/mysql-test/mysql-test-run

— Installing: /soft/mysql-5.7.26/build/mysql-test/lib/My/SafeProcess/my_safe_process

— Up-to-date: /soft/mysql-5.7.26/build/mysql-test/lib/My/SafeProcess/my_safe_process

— Installing: /soft/mysql-5.7.26/build/mysql-test/lib/My/SafeProcess/Base.pm

— Installing: /soft/mysql-5.7.26/build/support-files/mysqld_multi.server

— Installing: /soft/mysql-5.7.26/build/support-files/mysql-log-rotate

— Installing: /soft/mysql-5.7.26/build/support-files/magic

— Installing: /soft/mysql-5.7.26/build/share/aclocal/mysql.m4

— Installing: /soft/mysql-5.7.26/build/support-files/mysql.server

配置mysql参数,只是设置几个简单的mysql运行参数

[mysql@gbase mysql-5.7.26]$ cd build/etc

[mysql@gbase etc]$ pwd

/soft/mysql-5.7.26/build/etc

[mysql@gbase etc]$ vi my.cnf

[mysqld]

basedir=/soft/mysql-5.7.26/build/

datadir=/soft/mysql-5.7.26/build/data

bind-address=0.0.0.0

user=mysql

port=3306

log-error=/soft/mysql-5.7.26/build/data/mysql.err

pid-file=/soft/mysql-5.7.26/build/data/mysqld.pid

socket = /soft/mysql-5.7.26/build/data/mysql.sock

character-set-server=utf8mb4

default-storage-engine=INNODB

explicit_defaults_for_timestamp = true

[mysql@gbase build]$ bin/mysqld –defaults-file=etc/my.cnf –initialize-insecure

[mysql@gbase build]$ more data/mysql.err

2021-09-27T00:22:49.060540Z 0 [Warning] Changed limits: max_open_files: 1024 (requested 5000)

2021-09-27T00:22:49.060786Z 0 [Warning] Changed limits: table_open_cache: 431 (requested 2000)

2021-09-27T00:22:59.734768Z 0 [Warning] InnoDB: New log files created, LSN=45790

2021-09-27T00:23:01.122752Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.

2021-09-27T00:23:01.272820Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 12e47d2b-1f29-11ec-a401-005056a31fca.

2021-09-27T00:23:01.290654Z 0 [Warning] Gtid table is not ready to be used. Table ‘mysql.gtid_executed’ cannot be opened.

2021-09-27T00:23:01.293896Z 1 [Warning] root@localhost is created with an empty password ! Please consider switching off the –initialize-insecure option.

启动mysql

[mysql@gbase build]$ bin/mysqld_safe –user=mysql &

[1] 23685

[mysql@gbase build]$ 2021-09-27T00:30:29.012767Z mysqld_safe Logging to ‘/var/log/mariadb/mariadb.log’.

2021-09-27T00:30:29.097420Z mysqld_safe Starting mysqld daemon with databases from /soft/mysql-5.7.26/build/data

2021-09-27T00:30:30.910622Z mysqld_safe mysqld from pid file /var/run/mariadb/mariadb.pid ended

配置自动启动MySQL

[root@gbase log]# cp /soft/mysql-5.7.26/build/support-files/mysql.server /etc/init.d/mysqld

[root@gbase log]# systemctl start mysqld

[root@gbase log]# systemctl status mysqld

鈼[0m mysqld.service – LSB: start and stop MySQL

Loaded: loaded (/etc/rc.d/init.d/mysqld; bad; vendor preset: disabled)

Active: active (running) since Mon 2021-09-27 08:33:57 CST; 6s ago

Docs: man:systemd-sysv-generator(8)

Process: 24236 ExecStart=/etc/rc.d/init.d/mysqld start (code=exited, status=0/SUCCESS)

Tasks: 28

CGroup: /system.slice/mysqld.service

鈹溾攢24252 /bin/sh /soft/mysql-5.7.26/build//bin/mysqld_safe –datadir=/soft/mysql-5.7.26/build/data –pid-file=/soft/mysql-5.7.26/build/data/mysqld.pid

鈹斺攢24542 /soft/mysql-5.7.26/build/bin/mysqld –basedir=/soft/mysql-5.7.26/build/ –datadir=/soft/mysql-5.7.26/build/data –plugin-dir=/soft/mysql-5.7.26/build//lib/plugin –user=mysql –log-error=/var/log/mariadb/mariadb.l…

Sep 27 08:33:55 gbase systemd[1]: Starting LSB: start and stop MySQL…

Sep 27 08:33:57 gbase mysqld[24236]: Starting MySQL.. SUCCESS!

Sep 27 08:33:57 gbase systemd[1]: Started LSB: start and stop MySQL.

使用 VSCode 远程访问代码

首先改设置, 左下角 管理(?) -> 设置, 搜 “remote.SSH”, 勾选 remote.SSH.showLoginTerminal

在 VSCode 主界面 ctrl+shift+p 选 Remote.SSH: Connect to host, 输入 root@









然后就可以从侧边栏打开项目路径了, 点击左边的资源管理器,点击打开文件夹,在下图蓝框处输入mysql源码路径(注意不是编译后的运行程序路径是源码解压路径,我的环境源码路径为/soft/mysql-5.7.26,这里我还向下选择sql目录,因为mysql的大多数核心代码在该目录下,如main函数)

安装一些需要的扩展, 如:
? C/C++ IntelliSense, debugging, and code browsing

使用 VSCode 和 gdbserver 远程调试 mysql 代码

在远程 Linux 机器上运行如下代码:

[mysql@gbase ~]$ gdbserver localhost:2333 /soft/mysql-5.7.26/build/bin/mysqld –defaults-file=/soft/mysql-5.7.26/build/etc/my.cnf

Process /soft/mysql-5.7.26/build/bin/mysqld created; pid = 28184

Listening on port 2333

远程 Linux 机器 IP 是 192.168.1.249 gdbserver 的端口设为 2333, 在 VSCode 机器上, 进入菜单 调试 -> 添加配置, 会生成一个配置文件 SSH之后的项目根目录/.vscode/launch.json, 将其修改如下:


{

// Use IntelliSense to learn about possible attributes.

// Hover to view descriptions of existing attributes.

// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387

“version”: “0.2.0”,

“configurations”: [

{

“name”: “gdb Remote Launch”,

“type”: “cppdbg”,

“request”: “launch”,

“program”: “/soft/mysql-5.7.26/build/bin/mysqld”,

“args”: [],

“stopAtEntry”: true,

“cwd”: “${workspaceFolder}”,

“environment”: [],

“externalConsole”: false,

“MIMode”: “gdb”,

“miDebuggerPath”: “/usr/bin/gdb”,

“miDebuggerArgs”: “gdb”,

“linux”: {

“MIMode”: “gdb”,

“miDebuggerPath”: “/usr/bin/gdb”,

“miDebuggerServerAddress”: “192.168.1.249:2333”,

},

“logging”: {

“moduleLoad”: false,

“engineLogging”: true,

“trace”: false

},

“setupCommands”: [

{

“description”: “Enable pretty-printing for gdb”,

“text”: “-enable-pretty-printing”,

“ignoreFailures”: true

}

]

}

]

}

几个注意的地方:

? 应该是 “request”: “launch”, 不是 “attach”, 此后也并不需要记录进程ID

? 需要填对 “miDebuggerServerAddress”: “192.168.1.248:2333”, 有这个设置才会开启 gdb 远程调试

? “engineLogging”: true 可以看到 gdb 自身的详细消息

? 必须是 “externalConsole”: false 否则报错

? /soft/mysql-5.7.26/build/bin/mysqld 在 gdbserver 和 launch.json 里都要填一次,即mysql编译后的启动程序

之后就可以使用调试功能了, 添加断点, 监视等等, 如图:

MySQL load xml加载数据

load xml加载数据
load xml语法如下:

LOAD XML [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name'
[REPLACE | IGNORE]
INTO TABLE [db_name.]tbl_name
[CHARACTER SET charset_name]
[ROWS IDENTIFIED BY '<tagname>']
[IGNORE number {LINES | ROWS}]
[(field_name_or_user_var
[, field_name_or_user_var] ...)]
[SET col_name={expr | DEFAULT},
[, col_name={expr | DEFAULT}] ...]

load xml语句从xml文件中读取数据加载到数据表。file_name必须是文本字符形式且使用单引号将其括起来。在rows identified by选项的tagname子句必须也是文本字符形式并且必须使用<>括号括起来最后还要用单引号将其括起来。

load xml实际上是以xml输出模式来运行mysql客户端的一种补充。为了将表数据写入xml文件,可以调用带有–xml和-e选项的mysql客户端,例如:

[mysql@localhost ~]$ mysql -uroot -pabcd$123 cs --xml -e 'select * from cs.t' >t.xml
mysql: [Warning] Using a password on the command line interface can be insecure.
[mysql@localhost ~]$ ls -lrt
-rw-r--r--. 1 mysql mysql 216 5月 27 16:13 t.xml
[mysql@localhost ~]$ cat t.xml
<?xml version="1.0"?>

<resultset statement="select * from cs.t
" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<field name="id">3</field>
<field name="val" xsi:nil="true" />
</row>
</resultset>

为了将这个xml文件中的数据读回到表中,可以使用load xml infile。默认情况下<row>元属就相当于表行,但这可以使用rows identified by子句进行修改。

这个语句支持三种不同的xml格式:
.列名与列值作为属性值:

<row column1="value1" column2="value2" .../>

.列名作为标记且列值作为这些标记的内容:

<row>
<column1>value1</column1>
<column2>value2</column2>
</row>

.列名是<field>标记的name属性并且列值是这些标记的内容:

<row>
<field name='column1'>value1</field>
<field name='column2'>value2</field>
</row>

这种格式也是其实MySQL工具使用的格式,比如mysqldump。

所有三种格式可以同时用于相同的xml文件,导入过程会自动检测每一行的格式并正确解析它。标记是根据标记或属性名称和列名进行匹配的

下面创建一个测试表person,创建语句如下:

mysql> CREATE TABLE person (
-> person_id INT NOT NULL PRIMARY KEY,
-> fname VARCHAR(40) NULL,
-> lname VARCHAR(40) NULL,
-> created TIMESTAMP
-> );
Query OK, 0 rows affected (0.14 sec)

下面假设我们有一个简单的xml文件person.xml,其内容如下(这里使用了三种格式来描述行数据):

<list>
<person person_id="1" fname="Kapek" lname="Sainnouine"/>
<person><person_id>2</person_id><fname>Sajon</fname><lname>Rondela</lname></person>
<person><field name="person_id">3</field><field name="fname">Likame</field><field name="lname">Orrtmons</field></person>
</list>

为了将person.xml中的数据导入person表,可以执行以下语句:

mysql> load xml local infile 'person.xml' into table person rows identified by '<person>';
Query OK, 3 rows affected (0.02 sec)
Records: 3 Deleted: 0 Skipped: 0 Warnings: 0

rows identified by '<person>'子句意味着xml文件中的每个<person>元属就相当于表中的一行数据。

上面加载语句返回信息显示有3行数据被导入person表,执行简单的select语句来进行验证:

mysql> select * from person;
+-----------+--------+------------+---------+
| person_id | fname | lname | created |
+-----------+--------+------------+---------+
| 1 | Kapek | Sainnouine | NULL |
| 2 | Sajon | Rondela | NULL |
| 3 | Likame | Orrtmons | NULL |
+-----------+--------+------------+---------+
3 rows in set (0.01 sec)

这表明,如前面所述,3种允许的XML格式中的任何一种或所有三种都可以出现在单个文件中,并使用LOAD XML读取。

与刚才所示的导入操作相反–即将MySQL表数据转储到XML文件中–可以使用系统shell中的MySQL客户机来完成,如下所示:

[mysql@localhost ~]$ mysql -uroot -pabcd$123 --xml -e 'select * from cs.person' >person_dump.xml
mysql: [Warning] Using a password on the command line interface can be insecure.
[mysql@localhost ~]$ ls -lrt
-rw-r--r--. 1 mysql mysql 641 5月 27 16:00 person.xml
-rw-r--r--. 1 mysql mysql 641 5月 27 16:52 person_dump.xml
[mysql@localhost ~]$ cat person_dump.xml
<?xml version="1.0"?>

<resultset statement="select * from cs.person
" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<field name="person_id">1</field>
<field name="fname">Kapek</field>
<field name="lname">Sainnouine</field>
<field name="created" xsi:nil="true" />
</row>

<row>
<field name="person_id">2</field>
<field name="fname">Sajon</field>
<field name="lname">Rondela</field>
<field name="created" xsi:nil="true" />
</row>

<row>
<field name="person_id">3</field>
<field name="fname">Likame</field>
<field name="lname">Orrtmons</field>
<field name="created" xsi:nil="true" />
</row>

可以通过创建一个person表的副本并导入这个dump文件到新表中来验证这个dump的有效性,例如:

mysql> create table person1 like person;
Query OK, 0 rows affected (0.22 sec)

mysql> select * from person1;
Empty set (0.00 sec)

mysql> load xml local infile 'person_dump.xml' into table person1;
Query OK, 3 rows affected (0.04 sec)
Records: 3 Deleted: 0 Skipped: 0 Warnings: 0

mysql> select * from person1;
+-----------+--------+------------+---------+
| person_id | fname | lname | created |
+-----------+--------+------------+---------+
| 1 | Kapek | Sainnouine | NULL |
| 2 | Sajon | Rondela | NULL |
| 3 | Likame | Orrtmons | NULL |
+-----------+--------+------------+---------+
3 rows in set (0.00 sec)

不要求XML文件中的每个字段都与对应表中的列相匹配。没有相应列的字段将被跳过。可以首先清空person1表并删除created列,然后使用我们刚才使用的LOAD XML语句,如下所示:

mysql> truncate table person1;
Query OK, 0 rows affected (0.08 sec)

mysql> alter table person1 drop column created;
Query OK, 0 rows affected (0.16 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> show create table person1\G
*************************** 1. row ***************************
Table: person1
Create Table: CREATE TABLE `person1` (
`person_id` int(11) NOT NULL,
`fname` varchar(40) DEFAULT NULL,
`lname` varchar(40) DEFAULT NULL,
PRIMARY KEY (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

mysql> load xml local infile 'person_dump.xml' into table person1;
Query OK, 3 rows affected (0.04 sec)
Records: 3 Deleted: 0 Skipped: 0 Warnings: 0

mysql> select * from person1;
+-----------+--------+------------+
| person_id | fname | lname |
+-----------+--------+------------+
| 1 | Kapek | Sainnouine |
| 2 | Sajon | Rondela |
| 3 | Likame | Orrtmons |
+-----------+--------+------------+
3 rows in set (0.00 sec)

在XML文件的每一行中给出字段的顺序不影响LOAD XML的操作;字段顺序可以随行变化,不需要与表中相应列的顺序相同。

如前所述,您可以使用一个或多个XML字段的列表(field_name_or_user_var,…)或用户变量(存储相应的字段值以供以后使用)。当您希望将XML文件中的数据插入到名称与XML字段名称不匹配的表列中时,用户变量可能特别有用。为了了解其工作原理,我们首先创建一个名为individual的表,其结构与person表相匹配,但其列的名称不同。

mysql> create table individual (
-> individual_id int not null primary key,
-> name1 varchar(40) null,
-> name2 varchar(40) null,
-> made timestamp
-> );
Query OK, 0 rows affected (0.13 sec)

在这种情况下,不能简单地将XML文件直接加载到表中,因为字段名和列名不匹配:

mysql> load xml local infile 'person_dump.xml' into table cs.individual;
Query OK, 1 row affected, 15 warnings (0.04 sec)
Records: 8 Deleted: 0 Skipped: 7 Warnings: 15

mysql> show warnings\G
*************************** 1. row ***************************
Level: Warning
Code: 1263
Message: Column set to default value; NULL supplied to NOT NULL column 'individual_id' at row 1
*************************** 2. row ***************************
Level: Warning
Code: 1062
Message: Duplicate entry '0' for key 'PRIMARY'
*************************** 3. row ***************************
Level: Warning
Code: 1263
Message: Column set to default value; NULL supplied to NOT NULL column 'individual_id' at row 2
*************************** 4. row ***************************
Level: Warning
Code: 1062
Message: Duplicate entry '0' for key 'PRIMARY'
*************************** 5. row ***************************
Level: Warning
Code: 1263
Message: Column set to default value; NULL supplied to NOT NULL column 'individual_id' at row 3
*************************** 6. row ***************************
Level: Warning
Code: 1062
Message: Duplicate entry '0' for key 'PRIMARY'
*************************** 7. row ***************************
Level: Warning
Code: 1263
Message: Column set to default value; NULL supplied to NOT NULL column 'individual_id' at row 4
*************************** 8. row ***************************
Level: Warning
Code: 1062
Message: Duplicate entry '0' for key 'PRIMARY'
*************************** 9. row ***************************
Level: Warning
Code: 1263
Message: Column set to default value; NULL supplied to NOT NULL column 'individual_id' at row 5
*************************** 10. row ***************************
Level: Warning
Code: 1062
Message: Duplicate entry '0' for key 'PRIMARY'
*************************** 11. row ***************************
Level: Warning
Code: 1263
Message: Column set to default value; NULL supplied to NOT NULL column 'individual_id' at row 6
*************************** 12. row ***************************
Level: Warning
Code: 1062
Message: Duplicate entry '0' for key 'PRIMARY'
*************************** 13. row ***************************
Level: Warning
Code: 1263
Message: Column set to default value; NULL supplied to NOT NULL column 'individual_id' at row 7
*************************** 14. row ***************************
Level: Warning
Code: 1062
Message: Duplicate entry '0' for key 'PRIMARY'
*************************** 15. row ***************************
Level: Warning
Code: 1263
Message: Column set to default value; NULL supplied to NOT NULL column 'individual_id' at row 8
*************************** 16. row ***************************
Level: Warning
Code: 1062
Message: Duplicate entry '0' for key 'PRIMARY'
16 rows in set (0.00 sec)

mysql> select * from individual;
+---------------+-------+-------+------+
| individual_id | name1 | name2 | made |
+---------------+-------+-------+------+
| 0 | NULL | NULL | NULL |
+---------------+-------+-------+------+
1 row in set (0.00 sec)

这是因为MySQL服务器查找与目标表的列名匹配的字段名。您可以通过将字段值选择到用户变量中来解决这个问题,然后使用SET将目标表的列设置为这些变量的值。您可以在一个语句中执行这两个操作,如下所示:

mysql> load xml local infile 'person_dump.xml' into table cs.individual (@person_id,@fname,@lname,@created)
-> set individual_id=@person_id,name1=@fname,name2=@lname,made=@created;
Query OK, 8 rows affected (0.03 sec)
Records: 8 Deleted: 0 Skipped: 0 Warnings: 0

mysql> select * from individual;
+---------------+--------+------------+------+
| individual_id | name1 | name2 | made |
+---------------+--------+------------+------+
| 1 | Kapek | Sainnouine | NULL |
| 2 | Sajon | Rondela | NULL |
| 3 | Likame | ?rrtmons | NULL |
| 4 | Slar | Manlanth | NULL |
| 5 | Stoma | Milu | NULL |
| 6 | Nirtam | Skl?d | NULL |
| 7 | Sungam | Dulb?d | NULL |
| 8 | Sraref | Encmelt | NULL |
+---------------+--------+------------+------+
8 rows in set (0.00 sec)

用户变量的名称必须与XML文件中相应字段的名称匹配,并添加必要的@前缀,表示它们是变量。用户变量不需要按照与相应字段相同的顺序列出或分配。

使用rows identified by ‘<tagname>’子句,它可以从相同的XML文件中将数据导入有不同定义的表。例如,假设有一个名叫address.xml的文件:

<?xml version="1.0"?>
<list>
<person person_id="1">
<fname>Robert</fname>
<lname>Jones</lname>
<address address_id="1" street="Mill Creek Road" zip="45365" city="Sidney"/>
<address address_id="2" street="Main Street" zip="28681" city="Taylorsville"/>
</person>
<person person_id="2">
<fname>Mary</fname>
<lname>Smith</lname>
<address address_id="3" street="River Road" zip="80239" city="Denver"/>
<!-- <address address_id="4" street="North Street" zip="37920" city="Knoxville"/> -->
</person>
</list>

可以再次使用之前使用的person表,在删除表中记录后显示表结构信息:

mysql> truncate table person;
Query OK, 0 rows affected (0.18 sec)

mysql> show create table person\G
*************************** 1. row ***************************
Table: person
Create Table: CREATE TABLE `person` (
`person_id` int(11) NOT NULL,
`fname` varchar(40) DEFAULT NULL,
`lname` varchar(40) DEFAULT NULL,
`created` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)

现在使用下面的create table语句来创建一个名叫address的表:

mysql> CREATE TABLE address (
-> address_id INT NOT NULL PRIMARY KEY,
-> person_id INT NULL,
-> street VARCHAR(40) NULL,
-> zip INT NULL,
-> city VARCHAR(40) NULL,
-> created TIMESTAMP
-> );
Query OK, 0 rows affected (0.13 sec)

为了将数据从XML文件中导入到person表中,执行下面的load xml语句,它是通过<person>元素来指定一行数据:

mysql> load xml local infile 'address.xml' into table person rows identified by '<person>';
Query OK, 2 rows affected (0.13 sec)
Records: 2 Deleted: 0 Skipped: 0 Warnings: 0

现在来验证被导入的数据:

mysql> select * from person;
+-----------+--------+-------+---------+
| person_id | fname | lname | created |
+-----------+--------+-------+---------+
| 1 | Robert | Jones | NULL |
| 2 | Mary | Smith | NULL |
+-----------+--------+-------+---------+
2 rows in set (0.00 sec)

因为address.xml文件中的<address>元素在表person中没有相关联的列,因此会被跳过。

为了将address.xml文件中的<address>元素导入到address表中,执行下面的语句:

mysql> load xml local infile 'address.xml' into table address rows identified by '<address>';
Query OK, 3 rows affected (0.06 sec)
Records: 3 Deleted: 0 Skipped: 0 Warnings: 0

现在可以看到<address>元素表示的数据被导入address表了

mysql> select * from address;
+------------+-----------+-----------------+-------+--------------+---------+
| address_id | person_id | street | zip | city | created |
+------------+-----------+-----------------+-------+--------------+---------+
| 1 | 1 | Mill Creek Road | 45365 | Sidney | NULL |
| 2 | 1 | Main Street | 28681 | Taylorsville | NULL |
| 3 | 2 | River Road | 80239 | Denver | NULL |
+------------+-----------+-----------------+-------+--------------+---------+
3 rows in set (0.00 sec)

XML文件中被注释掉的<address>元素所表示的数据没有被导入。然而,因为在address表中有person_id列,因此每个<address>元素的父元素<person>的person_id属性值被导入了address表

安全考虑
与LOAD DATA语句一样,将XML文件从客户机主机传输到服务器主机是由MySQL服务器发起的。理论上,可以构建一个打过补丁的服务器,它将告诉客户机程序传输服务器选择的文件,而不是客户机在LOAD XML语句中命名的文件。这样的服务器可以访问客户机主机上客户机用户具有读访问权的任何文件。

在Web环境中,客户机通常从Web服务器连接到MySQL。可以对MySQL服务器运行任何命令的用户可以使用LOAD XML LOCAL读取Web服务器进程具有读访问权的任何文件。在这个环境中,与MySQL服务器相关的客户机实际上是Web服务器,而不是由连接到Web服务器的用户运行的远程程序

通过使用–local-infile=0或–local-infile=OFF启动服务器,可以禁止从客户机加载XML文件。当启动mysql客户端时,也可以使用这个选项来在客户端会话期间禁用LOAD XML

为了防止客户端从服务器上加载XML文件,不要将FILE特权授予相应的MySQL用户帐户,如果客户端用户帐户已经拥有该特权,则取消该特权。

MySQL通过通用列索引来提供一个JSON列索引

通过通用列索引来提供一个JSON列索引,不能直接对JSON列进行索引。要创建间接引用此类列的索引,可以定义一个生成的列,提取应该索引的信息,然后在生成的列上创建索引,如本例所示

mysql> CREATE TABLE jemp (
    -> c JSON,
    -> g INT GENERATED ALWAYS AS (c->"$.id"),
    -> INDEX i (g)
    -> );
Query OK, 0 rows affected (0.12 sec)

mysql> INSERT INTO jemp (c) VALUES
    -> ('{"id": "1", "name": "Fred"}'), ('{"id": "2", "name": "Wilma"}'),
    -> ('{"id": "3", "name": "Barney"}'), ('{"id": "4", "name": "Betty"}');
Query OK, 4 rows affected (0.04 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> SELECT c->>"$.name" AS name  FROM jemp WHERE g > 2;
+--------+
| name   |
+--------+
| Barney |
| Betty  |
+--------+
2 rows in set (0.00 sec)

mysql> EXPLAIN SELECT c->>"$.name" AS name  FROM jemp WHERE g > 2\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: jemp
   partitions: NULL
         type: range
possible_keys: i
          key: i
      key_len: 5
          ref: NULL
         rows: 2
     filtered: 100.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select json_unquote(json_extract(`mysql`.`jemp`.`c`,'$.name')) AS `name` from `mysql`.`jemp` where (`mysql`.`jemp`.`g` > 2)
1 row in set (0.00 sec)

我们已经包装了本例中最后一条语句的输出,以适应查看区域。

在MySQL 5.7.9及以后的版本中支持->操作符。从MySQL 5.7.13开始支持->>操作符

当对一个select或其它包含一个或多个使用->或->>操作符表达式的SQL语句时使用explain时,这些表达式将被翻译成等价的json_extract()和(如果需要)json_unquote()代替,例如下面的explain语句使用show warnings立即输出结果:

mysql> EXPLAIN SELECT c->>"$.name"  FROM jemp WHERE g > 2 ORDER BY c->"$.name"\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: jemp
   partitions: NULL
         type: range
possible_keys: i
          key: i
      key_len: 5
          ref: NULL
         rows: 2
     filtered: 100.00
        Extra: Using where; Using filesort
1 row in set, 1 warning (0.00 sec)

mysql> show warnings\G
*************************** 1. row ***************************
  Level: Note
   Code: 1003
Message: /* select#1 */ select json_unquote(json_extract(`mysql`.`jemp`.`c`,'$.name')) AS `c->>"$.name"` from `mysql`.`jemp` where (`mysql`.`jemp`.`g` > 2) order by json_extract(`mysql`.`jemp`.`c`,'$.name')
1 row in set (0.00 sec)

可以看到->和->>操作符使用json_extract()和json_unquote()函数来描述。这种技术可以被用来为那些不能被直接索引的间接引用列提供索引 ,比如geometry列。

DM7使用dmrestore工具利用不同数据库的归档恢复数据库

使用dmrestore工具利用不同数据库的归档恢复数据库
使用不同库的归档恢复数据库,应用场景如下:
1. 创建一个源库D1;
2. 做一个备份B1;
3. 在D1上做一些操作,目的是生成一些归档A1;
4. 创建一个新库D2;
5. 用B1+A1还原恢复;
6. 在D2上做一些操作,生成一些归档A2;
7. 现在有了B1,A1,A2, 理论上应该可以恢复出一个最新状态的D2。

1) 创建源库D1,即待备份的数据库,然后启动数据库并配置归档,归档目录为/dm_home/dmdba/dmdbms/data/d1_arch。

[dmdba@shard1 data]$ dminit path=/dm_home/dmdba/dmdbms/data db_name=d1 instance_name=d1 port_num=5237 unicode_flag=0
initdb V7.1.6.46-Build(2018.02.08-89107)ENT
db version: 0x7000a
file dm.key not found, use default license!
License will expire in 14 day(s) on 2020-08-18

log file path: /dm_home/dmdba/dmdbms/data/d1/d101.log


log file path: /dm_home/dmdba/dmdbms/data/d1/d102.log

write to dir [/dm_home/dmdba/dmdbms/data/d1].
create dm database success. 2020-08-04 12:53:42

[root@shard1 root]# ./dm_service_installer.sh -i /dm_home/dmdba/dmdbms/data/d1/dm.ini -p d1 -t dmserver
ln -s '/usr/lib/systemd/system/DmServiced1.service' '/etc/systemd/system/multi-user.target.wants/DmServiced1.service'
Finished to create the service (DmServiced1)

[root@shard1 root]# service DmServiced1 start
Redirecting to /bin/systemctl start DmServiced1.service

–连接数据库配置归档

[dmdba@shard1 backup]$ disql SYSDBA/SYSDBA@localhost:5237

Server[localhost:5237]:mode is normal, state is open
login used time: 10.168(ms)
disql V7.1.6.46-Build(2018.02.08-89107)ENT
Connected to: DM 7.1.6.46
SQL> alter database mount;
executed successfully
used time: 00:00:01.844. Execute id is 0.
SQL> alter database add archivelog 'dest=/dm_home/dmdba/dmdbms/data/d1_arch,type=local,file_size=256,space_limit=10240';
executed successfully
used time: 19.055(ms). Execute id is 0.
SQL> alter database archivelog;
executed successfully
used time: 28.622(ms). Execute id is 0.
SQL> alter database open;
executed successfully
used time: 666.842(ms). Execute id is 0.
SQL> select permanent_magic;

LINEID PERMANENT_MAGIC
---------- ---------------
1 -640527680

used time: 2.234(ms). Execute id is 807.
SQL> select db_magic from v$rlog;

LINEID DB_MAGIC
---------- -----------
1 -181202026

used time: 1.146(ms). Execute id is 808.

2)对数据库d1执行完全备份,备份名为B1

SQL> backup database full to b1 bakfile '/dm_home/dmdba/dmdbms/backup/b1.bak';
executed successfully
used time: 00:00:01.779. Execute id is 6.

3)在D1上做一些操作,目的是生成一些归档A1

SQL> create table tab_for_recover_01(c1 int);
executed successfully
used time: 14.595(ms). Execute id is 810.

SQL> begin
2 for i in 1 .. 100000 loop
3 insert into tab_for_recover_01 values(i);
4 end loop;
5 commit;
6 end;
7 /
DMSQL executed successfully
used time: 00:00:01.578. Execute id is 813.

[root@shard1 root]# service DmServiced1 stop
Redirecting to /bin/systemctl stop DmServiced1.service

4) 创建源库D2,即待还原的数据库,然后启动数据库并配置归档,归档目录为/dm_home/dmdba/dmdbms/data/d2_arch。

[dmdba@shard1 data]$ dminit path=/dm_home/dmdba/dmdbms/data db_name=d2 instance_name=d2 port_num=5238 unicode_flag=0
initdb V7.1.6.46-Build(2018.02.08-89107)ENT
db version: 0x7000a
file dm.key not found, use default license!
License will expire in 14 day(s) on 2020-08-18

log file path: /dm_home/dmdba/dmdbms/data/d2/d201.log


log file path: /dm_home/dmdba/dmdbms/data/d2/d202.log

write to dir [/dm_home/dmdba/dmdbms/data/d2].
create dm database success. 2020-08-04 13:10:20

[root@shard1 root]# ./dm_service_installer.sh -i /dm_home/dmdba/dmdbms/data/d2/dm.ini -p d2 -t dmserver
ln -s '/usr/lib/systemd/system/DmServiced2.service' '/etc/systemd/system/multi-user.target.wants/DmServiced2.service'
Finished to create the service (DmServiced2)
[root@shard1 root]# service DmServiced2 start
Redirecting to /bin/systemctl start DmServiced2.service

[dmdba@shard1 backup]$ disql SYSDBA/SYSDBA@localhost:5238

Server[localhost:5238]:mode is normal, state is open
login used time: 9.777(ms)
disql V7.1.6.46-Build(2018.02.08-89107)ENT
Connected to: DM 7.1.6.46
SQL> alter database mount;
executed successfully
used time: 00:00:01.878. Execute id is 0.
SQL> alter database add archivelog 'dest=/dm_home/dmdba/dmdbms/data/d2_arch,type=local,file_size=256,space_limit=10240';
executed successfully
used time: 32.468(ms). Execute id is 0.
SQL> alter database archivelog;
executed successfully
used time: 70.806(ms). Execute id is 0.
SQL> alter database open;
executed successfully
used time: 752.732(ms). Execute id is 0.

5)利用源库D1的备份B1及归档A1还原数据库到D2。

[root@shard1 root]# service DmServiced2 stop
Redirecting to /bin/systemctl stop DmServiced2.service

[dmdba@shard1 backup]$ dmrestore ini_path=/dm_home/dmdba/dmdbms/data/d2/dm.ini file=/dm_home/dmdba/dmdbms/backup/b1.bak archive_dir=/dm_home/dmdba/dmdbms/data/d1_arch
restore V7.1.6.46-Build(2018.02.08-89107)ENT
file dm.key not found, use default license!


backup sig: BA
backup tool version: 12595
backup db name: d1
backup db magic: -181202026
backup pemnt magic: -640527680
backup name: B1
backup type: full
backup level: online
backup range: database
backup description:
compressed level: 0
encrypt_type: 0
encrypt_id: 2052
rac node: 0
page check: 0
rlog encrypt: 0
external cipher id: 0
external hash id: 0
length in char: 0
use new hash: 1
backup time: 2020-08-04 13:26:27
page size: 8 KB
extent size: 16
case sensitive: 1
log page size: 512 B
charset: 0
data version: 0x7000A
sys version: V7.1.6.46-Build(2018.02.08-89107)ENT
enable policy: 0
mpp_timestamp: 1596518786
crc_check: TRUE
parallel type: 0
parallel info len: 0
backup db fil num: 4
archive flag: 1
backup with log: Yes
before backup LSN: 137137
after backup LSN: 137137


$bak_seq |$file_path |$size(K) |$used(K)
1|/dm_home/dmdba/dmdbms/backup/b1.bak | 32768.00| 15558.00


$file_seq |$type|$ts_name |$state |$size(K) |$seq_in_bak |$off_in_bak(B) |$len_in_bak(B) |$file_path |$mirror_path
1|DBF |SYSTEM |ONLINE | 21504| 1| 22528| 5095424|/dm_home/dmdba/dmdbms/data/d1/SYSTEM.DBF |
2|DBF |ROLL |ONLINE | 131072| 1| 5117952| 10780672|/dm_home/dmdba/dmdbms/data/d1/ROLL.DBF |
3|DBF |MAIN |ONLINE | 131072| 1| 15898624| 32768|/dm_home/dmdba/dmdbms/data/d1/MAIN.DBF |
4|LOG |ARCHLOG |ONLINE | 0| 1| 15931392| 0| |

Continue?[Y/N]:Y
restore bak_file: /dm_home/dmdba/dmdbms/backup/b1.bak ...
start restore database...
start restore file: /dm_home/dmdba/dmdbms/data/d2/SYSTEM.DBF(SYSTEM), pages: 622
end restore file: /dm_home/dmdba/dmdbms/data/d2/SYSTEM.DBF(SYSTEM)
start restore file: /dm_home/dmdba/dmdbms/data/d2/ROLL.DBF(ROLL), pages: 1316
end restore file: /dm_home/dmdba/dmdbms/data/d2/ROLL.DBF(ROLL)
start restore file: /dm_home/dmdba/dmdbms/data/d2/MAIN.DBF(MAIN), pages: 4
end restore file: /dm_home/dmdba/dmdbms/data/d2/MAIN.DBF(MAIN)
end restore database data files.


Apply archive log LSN from 137138 to 239573, time used:6.531s.
restore finished, code = 0!

restore successfully!
restore time used: 9133.827(ms)

6)在D2上做一些操作,生成一些归档A2;

[root@shard1 root]# service DmServiced2 start
Redirecting to /bin/systemctl start DmServiced2.service

[dmdba@shard1 backup]$ disql SYSDBA/SYSDBA@localhost:5238

Server[localhost:5238]:mode is normal, state is open
login used time: 10.015(ms)
disql V7.1.6.46-Build(2018.02.08-89107)ENT
Connected to: DM 7.1.6.46
SQL> select count(*) from tab_for_recover_01;

LINEID COUNT(*)
---------- --------------------
1 100000

used time: 3.284(ms). Execute id is 3.
SQL> begin
2 for i in 100001 .. 200000 loop
3 insert into tab_for_recover_01 values(i);
4 end loop;
5 commit;
6 end;
7 /
DMSQL executed successfully
used time: 00:00:01.428. Execute id is 4.
SQL> commit;
executed successfully
used time: 0.338(ms). Execute id is 5.
SQL> select count(*) from tab_for_recover_01;

LINEID COUNT(*)
---------- --------------------
1 200000

used time: 0.289(ms). Execute id is 6.

7)关闭数据库D2,利用备份文件B1、归档A1、A2还原数据库到D2。

[root@shard1 root]# service DmServiced2 stop
Redirecting to /bin/systemctl stop DmServiced2.service

利用备份文件B1、归档A1还原目标库

[dmdba@shard1 backup]$ dmrestore ini_path=/dm_home/dmdba/dmdbms/data/d2/dm.ini file=/dm_home/dmdba/dmdbms/backup/b1.bak archive_dir=/dm_home/dmdba/dmdbms/data/d1_arch
restore V7.1.6.46-Build(2018.02.08-89107)ENT
file dm.key not found, use default license!


backup sig: BA
backup tool version: 12595
backup db name: d1
backup db magic: -181202026
backup pemnt magic: -640527680
backup name: B1
backup type: full
backup level: online
backup range: database
backup description:
compressed level: 0
encrypt_type: 0
encrypt_id: 2052
rac node: 0
page check: 0
rlog encrypt: 0
external cipher id: 0
external hash id: 0
length in char: 0
use new hash: 1
backup time: 2020-08-04 13:26:27
page size: 8 KB
extent size: 16
case sensitive: 1
log page size: 512 B
charset: 0
data version: 0x7000A
sys version: V7.1.6.46-Build(2018.02.08-89107)ENT
enable policy: 0
mpp_timestamp: 1596518786
crc_check: TRUE
parallel type: 0
parallel info len: 0
backup db fil num: 4
archive flag: 1
backup with log: Yes
before backup LSN: 137137
after backup LSN: 137137


$bak_seq |$file_path |$size(K) |$used(K)
1|/dm_home/dmdba/dmdbms/backup/b1.bak | 32768.00| 15558.00


$file_seq |$type|$ts_name |$state |$size(K) |$seq_in_bak |$off_in_bak(B) |$len_in_bak(B) |$file_path |$mirror_path
1|DBF |SYSTEM |ONLINE | 21504| 1| 22528| 5095424|/dm_home/dmdba/dmdbms/data/d1/SYSTEM.DBF |
2|DBF |ROLL |ONLINE | 131072| 1| 5117952| 10780672|/dm_home/dmdba/dmdbms/data/d1/ROLL.DBF |
3|DBF |MAIN |ONLINE | 131072| 1| 15898624| 32768|/dm_home/dmdba/dmdbms/data/d1/MAIN.DBF |
4|LOG |ARCHLOG |ONLINE | 0| 1| 15931392| 0| |

Continue?[Y/N]:Y
restore bak_file: /dm_home/dmdba/dmdbms/backup/b1.bak ...
start restore database...
start restore file: /dm_home/dmdba/dmdbms/data/d2/SYSTEM.DBF(SYSTEM), pages: 622
end restore file: /dm_home/dmdba/dmdbms/data/d2/SYSTEM.DBF(SYSTEM)
start restore file: /dm_home/dmdba/dmdbms/data/d2/ROLL.DBF(ROLL), pages: 1316
end restore file: /dm_home/dmdba/dmdbms/data/d2/ROLL.DBF(ROLL)
start restore file: /dm_home/dmdba/dmdbms/data/d2/MAIN.DBF(MAIN), pages: 4
end restore file: /dm_home/dmdba/dmdbms/data/d2/MAIN.DBF(MAIN)
end restore database data files.


Apply archive log LSN from 137138 to 239573, time used:6.839s.
restore finished, code = 0!

restore successfully!
restore time used: 9586.006(ms)

查看归档A2的db_magic

[dmdba@shard1 d2_arch]$ ls -lrt
总用量 12984
-rw-r--r-- 1 dmdba dinstall 207872 8月 4 13:17 ARCHIVE_LOCAL1_20200804131521529_0.log
-rw-r--r-- 1 dmdba dinstall 268435456 8月 4 13:32 ARCHIVE_LOCAL1_20200804133104014_0.log

[dmdba@shard1 backup]$ dmrachk arch_fil=/dm_home/dmdba/dmdbms/data/d2_arch/ARCHIVE_LOCAL1_20200804131521529_0.log
rachk V7.1.6.46-Build(2018.02.08-89107)ENT
/*******************************************************************/
archive file /dm_home/dmdba/dmdbms/data/d2_arch/ARCHIVE_LOCAL1_20200804131521529_0.log itemize.
version : 0x7004
status : INACTIVE
n_rpags : 398
db_magic : 399359200
pemnt_magic : -1514196346
arch_lsn : 31701
arch_seq : 13564
clsn : 34492
next_seq : 13961
file len : 207872
file free : 207872
create time : 2020-08-04 13:15:21
close time : 2020-08-04 13:17:38
crc_check : TRUE
/*******************************************************************/

The SUMMARY(seqno[0]):
total files: 1
okey files: 1
fail file: 0
repeat file: 0

the rachk tool running cost 0.435 ms

[dmdba@shard1 backup]$ dmrachk arch_fil=/dm_home/dmdba/dmdbms/data/d2_arch/ARCHIVE_LOCAL1_20200804133104014_0.log
rachk V7.1.6.46-Build(2018.02.08-89107)ENT
/*******************************************************************/
archive file /dm_home/dmdba/dmdbms/data/d2_arch/ARCHIVE_LOCAL1_20200804133104014_0.log itemize.
version : 0x7004
status : INACTIVE
n_rpags : 25688
db_magic : 349450744
pemnt_magic : -640527680
arch_lsn : 239573
arch_seq : 13962
clsn : 343441
next_seq : 39649
file len : 13156352
file free : 13156352
create time : 2020-08-04 13:31:04
close time : 2020-08-04 13:40:35
crc_check : TRUE
/*******************************************************************/

The SUMMARY(seqno[0]):
total files: 1
okey files: 1
fail file: 0
repeat file: 0

the rachk tool running cost 0.394 ms

修改目标库D2的db_magic与A2的一致,A2的db_magic为349450744

[dmdba@shard1 d2]$ ls -lrt
总用量 544144
drwxr-xr-x 2 dmdba dinstall 6 8月 4 13:10 bak
-rw-r--r-- 1 dmdba dinstall 479 8月 4 13:10 sqllog.ini
drwxr-xr-x 2 dmdba dinstall 6 8月 4 13:10 HMAIN
-rw-r--r-- 1 dmdba dinstall 880 8月 4 13:10 dminit20200804131010.log
drwxr-xr-x 2 dmdba dinstall 6 8月 4 13:14 trace
-rw-r--r-- 1 dmdba dinstall 12 8月 4 13:14 rep_conflict.log
-rw-r--r-- 1 dmdba dinstall 269 8月 4 13:15 dmarch.ini
-rw-r--r-- 1 dmdba dinstall 220 8月 4 13:43 dminst.sys
-rw-r--r-- 1 dmdba dinstall 10485760 8月 4 13:43 TEMP.DBF
-rw-r--r-- 1 dmdba dinstall 5120 8月 4 13:43 dm.ctl
drwxr-xr-x 2 dmdba dinstall 4096 8月 4 13:43 ctl_bak
-rw-r--r-- 1 dmdba dinstall 134217728 8月 4 13:43 ROLL.DBF
-rw-r--r-- 1 dmdba dinstall 134217728 8月 4 13:43 MAIN.DBF
-rw-r--r-- 1 dmdba dinstall 268435456 8月 4 13:43 d201.log
-rw-r--r-- 1 dmdba dinstall 268435456 8月 4 13:43 d202.log
-rw-r--r-- 1 dmdba dinstall 633 8月 4 13:43 dm_service.prikey
-rw-r--r-- 1 dmdba dinstall 40845 8月 4 13:43 dm.ini
-rw-r--r-- 1 dmdba dinstall 22020096 8月 4 13:43 SYSTEM.DBF

[dmdba@shard1 d2]$ dmmdf type=1 file=SYSTEM.DBF
dmmdf V7.1.6.46-Build(2018.02.08-89107)ENT
**********************************************************
1 db_magic=-844697348
2 next_trxid=1127
3 pemnt_magic=-640527680
**********************************************************
Please input which parameter you want to change(1-3), q to quit: 1
Please input new value: 349450744
**********************************************************
1 db_magic=349450744
2 next_trxid=1127
3 pemnt_magic=-640527680
**********************************************************
Do you want to save the change to file (y/n): Y
Save to file success!

[dmdba@shard1 d2]$ dmmdf type=2 file=d201.log
dmmdf V7.1.6.46-Build(2018.02.08-89107)ENT
**********************************************************
1 sig = DMRLOG
2 ver = 7004
3 chksum = 0
4 dbversion = 0x7000a
5 sta = 0
6 n_magic = 35
7 db_magic = -844697348
8 clsn_fil = 0
10 next_seq = 39650
11 arch_seq = 0
12 len = 268435456
13 free = 4096
14 clsn = 239573
15 clsn_off = 4096
16 arch_lsn = 0
17 pemnt_magic = -640527680
18 fil_id = 0
19 crc_check = 1
**********************************************************
You can only reset sta(5) or db_magic (7) or clsn (14) or pemnt_magic(17) or fil_id(18).
Please input the num which one you want to change, q to quit: 7
Input the new value: 349450744
**********************************************************
1 sig = DMRLOG
2 ver = 7004
3 chksum = 0
4 dbversion = 0x7000a
5 sta = 0
6 n_magic = 35
7 db_magic = 349450744
8 clsn_fil = 0
10 next_seq = 39650
11 arch_seq = 0
12 len = 268435456
13 free = 4096
14 clsn = 239573
15 clsn_off = 4096
16 arch_lsn = 0
17 pemnt_magic = -640527680
18 fil_id = 0
19 crc_check = 1
**********************************************************
Do you want to quit and save the change to file (y/n): Y
Save to file success!
[dmdba@shard1 d2]$ dmmdf type=2 file=d202.log
dmmdf V7.1.6.46-Build(2018.02.08-89107)ENT
**********************************************************
1 sig = DMRLOG
2 ver = 7004
3 chksum = 0
4 dbversion = 0x7000a
5 sta = 0
6 n_magic = 35
7 db_magic = -844697348
8 clsn_fil = 0
10 next_seq = 0
11 arch_seq = 0
12 len = 268435456
13 free = 4096
14 clsn = 0
15 clsn_off = 0
16 arch_lsn = 0
17 pemnt_magic = -640527680
18 fil_id = 1
19 crc_check = 1
**********************************************************
You can only reset sta(5) or db_magic (7) or clsn (14) or pemnt_magic(17) or fil_id(18).
Please input the num which one you want to change, q to quit: 7
Input the new value: 349450744
**********************************************************
1 sig = DMRLOG
2 ver = 7004
3 chksum = 0
4 dbversion = 0x7000a
5 sta = 0
6 n_magic = 35
7 db_magic = 349450744
8 clsn_fil = 0
10 next_seq = 0
11 arch_seq = 0
12 len = 268435456
13 free = 4096
14 clsn = 0
15 clsn_off = 0
16 arch_lsn = 0
17 pemnt_magic = -640527680
18 fil_id = 1
19 crc_check = 1
**********************************************************
Do you want to quit and save the change to file (y/n): Y
Save to file success!

利用归档A2恢复。

[dmdba@shard1 backup]$ dmrestore ini_path=/dm_home/dmdba/dmdbms/data/d2/dm.ini archive_dir=/dm_home/dmdba/dmdbms/data/d2_arch res_type=2
restore V7.1.6.46-Build(2018.02.08-89107)ENT
file dm.key not found, use default license!

Continue?[Y/N]:Y
try to apply archive log from LSN: 239573 to LSN: 9223372036854775807.

Apply archive log LSN from 239574 to 343441, time used:1.372s.

restore successfully!
restore time used: 2406.492(ms)

8)启动数据D2查看结果。

[root@shard1 root]# service DmServiced2 start
Redirecting to /bin/systemctl start DmServiced2.service

SQL> select count(*) from tab_for_recover_01;

LINEID COUNT(*)
---------- --------------------
1 200000

used time: 0.309(ms). Execute id is 4.

DM7使用dmrestore执行并行映射文件还原

使用dmrestore执行并行映射文件还原
对于并行备份产生的备份文件,系统支持利用还原工具对数据库进行并行还原。与并行备份一样,并行还原需要用户指定并行映射文件的存储位置。由于并行备份可能是增量备份,而备份的基础备份也有可能是并行备份,因此执行并行还原需要指定一个映射文件存放的目录,用于还原的并行备份的映射文件都存放在该目录下。并行还原能提高还原性能,使得数据服务迅速还原。需要说明的是,备份时的映射文件内容应与还原时映射文件内容保持一致,但这不是必需的,系统在还原前,会对用户设置的映射文件内容进行校验,判断映射文件内容是否与备份时映射文件内容兼容,保证系统能正确还原数据库。

创建并行映射文件

[dmdba@shard1 backup]$ vi bak.parallel
[DMHR,USERS]=/dm_home/dmdba/dmdbms/backup/backup1
[FG_PERSON]=/dm_home/dmdba/dmdbms/backup/backup2
[default]=/dm_home/dmdba/dmdbms/backup/backup3

创建数据库的备份文件

SQL> backup database full to para_bak bakfile '/dm_home/dmdba/dmdbms/backup/parallel.bak' parallel '/dm_home/dmdba/dmdbms/backup/bak.parallel';
executed successfully
used time: 00:00:12.628. Execute id is 164.

[dmdba@shard1 backup]$ ls -lrt
-rw-r--r-- 1 dmdba dinstall       146 8月   4 11:50 bak.parallel
drwxr-xr-x 2 dmdba dinstall        47 8月   4 12:10 backup3
drwxr-xr-x 2 dmdba dinstall        47 8月   4 12:10 backup2
drwxr-xr-x 2 dmdba dinstall        47 8月   4 12:10 backup1
-rw-r--r-- 1 dmdba dinstall  33554432 8月   4 12:10 parallel.bak
[dmdba@shard1 backup]$ cd backup1
[dmdba@shard1 backup1]$ ls -lrt
总用量 1512
-rw-r--r-- 1 dmdba dinstall 33554432 8月   4 12:10 DB_jydm_20200804121005000554_1.bak
[dmdba@shard1 backup1]$ cd ..
[dmdba@shard1 backup]$ cd backup2
[dmdba@shard1 backup2]$ ls -lrt
总用量 28
-rw-r--r-- 1 dmdba dinstall 33554432 8月   4 12:10 DB_jydm_20200804121005000554_1.bak
[dmdba@shard1 backup2]$ cd ..
[dmdba@shard1 backup]$ cd backup3
[dmdba@shard1 backup3]$ ls -lrt
总用量 390420
-rw-r--r-- 1 dmdba dinstall 402653184 8月   4 12:10 DB_jydm_20200804121005000554_1.bak

使用并行备份文件来还原数据库,并行映射文件为/dm_home/dmdba/dmdbms/backup/bak.parallel

[root@shard1 oracle]# service DmServicejydm stop
Redirecting to /bin/systemctl stop  DmServicejydm.service

[dmdba@shard1 backup]$ dmrestore ini_path=/dm_home/dmdba/dmdbms/data/jydm/dm.ini file=/dm_home/dmdba/dmdbms/backup/parallel.bak   parallel_dir=/dm_home/dmdba/dmdbms/backup/bak.parallel
restore V7.1.6.46-Build(2018.02.08-89107)ENT
file dm.key not found, use default license!


backup sig:            BA
backup tool version:   12595
backup db name:        jydm
backup db magic:       -848310636
backup pemnt magic:    1250320462
backup name:           PARA_BAK
backup type:           full
backup level:          online
backup range:          database
backup description:
compressed level:      0
encrypt_type:          0
encrypt_id:            2052
rac node:              0
page check:            0
rlog encrypt:          0
external cipher id:    0
external hash id:      0
length in char:        0
use new hash:          1
backup time:           2020-08-04 12:10:05
page size:             8 KB
extent size:           16
case sensitive:        1
log page size:         512 B
charset:               0
data version:          0x7000A
sys version:           V7.1.6.46-Build(2018.02.08-89107)ENT
enable policy:         0
mpp_timestamp:         1596514204
crc_check:             TRUE
parallel type:         1
parallel info len:     1536
backup db fil num:     9
archive flag:          1
backup with log:       Yes
before backup LSN:     32598802
after backup LSN:      32598813


$bak_seq |$file_path                                        |$size(K)       |$used(K)
        1|/dm_home/dmdba/dmdbms/backup/parallel.bak         |       32768.00|          47.50


$file_seq |$type|$ts_name       |$state    |$size(K)  |$seq_in_bak    |$off_in_bak(B) |$len_in_bak(B) |$file_path                                        |$mirror_path
         1|DBF  |SYSTEM         |ONLINE    |     23552|              1|              0|              0|/dm_home/dmdba/dmdbms/data/jydm/SYSTEM.DBF        |
         2|DBF  |ROLL           |ONLINE    |    229376|              1|              0|              0|/dm_home/dmdba/dmdbms/data/jydm/ROLL.DBF          |
         3|DBF  |MAIN           |ONLINE    |    305152|              1|              0|              0|/dm_home/dmdba/dmdbms/data/jydm/MAIN.DBF          |
         4|DBF  |BOOKSHOP       |ONLINE    |    153600|              1|              0|              0|/dm_home/dmdba/dmdbms/data/jydm/BOOKSHOP.DBF      |
         5|DBF  |DMHR           |ONLINE    |    131072|              1|              0|              0|/dm_home/dmdba/dmdbms/data/jydm/DMHR.DBF          |
         6|DBF  |USERS          |ONLINE    |     51200|              1|              0|              0|/dm_home/dmdba/dmdbms/data/jydm/users01.dbf       |
         7|DBF  |SYSAUX         |ONLINE    |    179200|              1|              0|              0|/dm_home/dmdba/dmdbms/data/jydm/SYSAWR.DBF        |
         8|DBF  |FG_PERSON      |ONLINE    |    131072|              1|              0|              0|/dm_home/dmdba/dmdbms/data/jydm/FG_PERSON.DBF     |
         9|LOG  |ARCHLOG        |ONLINE    |         0|              1|          44544|           4096|                                                  |


backup sig:            BA
backup tool version:   12595
backup db name:        jydm
backup db magic:       -848310636
backup pemnt magic:    1250320462
backup name:           PARA_BAK
backup type:           full
backup level:          online
backup range:          database
backup description:
compressed level:      0
encrypt_type:          0
encrypt_id:            2052
rac node:              0
page check:            0
rlog encrypt:          0
external cipher id:    0
external hash id:      0
length in char:        0
use new hash:          1
backup time:           2020-08-04 12:10:05
page size:             8 KB
extent size:           16
case sensitive:        1
log page size:         512 B
charset:               0
data version:          0x7000A
sys version:           V7.1.6.46-Build(2018.02.08-89107)ENT
enable policy:         0
mpp_timestamp:         1596514204
crc_check:             TRUE
parallel type:         2
parallel info len:     0
backup db fil num:     2
archive flag:          1
backup with log:       Yes
before backup LSN:     32598802
after backup LSN:      0


$bak_seq |$file_path                                        |$size(K)       |$used(K)
        1|/dm_home/dmdba/dmdbms/backup/backup1/DB_jydm_20200804121005000554_1.bak|       32768.00|        1510.00


$file_seq |$type|$ts_name       |$state    |$size(K)  |$seq_in_bak    |$off_in_bak(B) |$len_in_bak(B) |$file_path                                        |$mirror_path
         1|DBF  |DMHR           |ONLINE    |    131072|              1|          14336|         425984|/dm_home/dmdba/dmdbms/data/jydm/DMHR.DBF          |
         2|DBF  |USERS          |ONLINE    |     51200|              1|         440320|        1105920|/dm_home/dmdba/dmdbms/data/jydm/users01.dbf       |


backup sig:            BA
backup tool version:   12595
backup db name:        jydm
backup db magic:       -848310636
backup pemnt magic:    1250320462
backup name:           PARA_BAK
backup type:           full
backup level:          online
backup range:          database
backup description:
compressed level:      0
encrypt_type:          0
encrypt_id:            2052
rac node:              0
page check:            0
rlog encrypt:          0
external cipher id:    0
external hash id:      0
length in char:        0
use new hash:          1
backup time:           2020-08-04 12:10:05
page size:             8 KB
extent size:           16
case sensitive:        1
log page size:         512 B
charset:               0
data version:          0x7000A
sys version:           V7.1.6.46-Build(2018.02.08-89107)ENT
enable policy:         0
mpp_timestamp:         1596514204
crc_check:             TRUE
parallel type:         2
parallel info len:     0
backup db fil num:     1
archive flag:          1
backup with log:       Yes
before backup LSN:     32598802
after backup LSN:      0


$bak_seq |$file_path                                        |$size(K)       |$used(K)
        1|/dm_home/dmdba/dmdbms/backup/backup2/DB_jydm_20200804121005000554_1.bak|       32768.00|          26.00


$file_seq |$type|$ts_name       |$state    |$size(K)  |$seq_in_bak    |$off_in_bak(B) |$len_in_bak(B) |$file_path                                        |$mirror_path
         1|DBF  |FG_PERSON      |ONLINE    |    131072|              1|          10240|          16384|/dm_home/dmdba/dmdbms/data/jydm/FG_PERSON.DBF     |


backup sig:            BA
backup tool version:   12595
backup db name:        jydm
backup db magic:       -848310636
backup pemnt magic:    1250320462
backup name:           PARA_BAK
backup type:           full
backup level:          online
backup range:          database
backup description:
compressed level:      0
encrypt_type:          0
encrypt_id:            2052
rac node:              0
page check:            0
rlog encrypt:          0
external cipher id:    0
external hash id:      0
length in char:        0
use new hash:          1
backup time:           2020-08-04 12:10:05
page size:             8 KB
extent size:           16
case sensitive:        1
log page size:         512 B
charset:               0
data version:          0x7000A
sys version:           V7.1.6.46-Build(2018.02.08-89107)ENT
enable policy:         0
mpp_timestamp:         1596514204
crc_check:             TRUE
parallel type:         2
parallel info len:     0
backup db fil num:     5
archive flag:          1
backup with log:       Yes
before backup LSN:     32598802
after backup LSN:      0


$bak_seq |$file_path                                        |$size(K)       |$used(K)
        1|/dm_home/dmdba/dmdbms/backup/backup3/DB_jydm_20200804121005000554_1.bak|      393216.00|      390418.00


$file_seq |$type|$ts_name       |$state    |$size(K)  |$seq_in_bak    |$off_in_bak(B) |$len_in_bak(B) |$file_path                                        |$mirror_path
         1|DBF  |SYSTEM         |ONLINE    |     23552|              1|          26624|        6766592|/dm_home/dmdba/dmdbms/data/jydm/SYSTEM.DBF        |
         2|DBF  |ROLL           |ONLINE    |    229376|              1|        6793216|       10887168|/dm_home/dmdba/dmdbms/data/jydm/ROLL.DBF          |
         3|DBF  |MAIN           |ONLINE    |    305152|              1|       17680384|      270917632|/dm_home/dmdba/dmdbms/data/jydm/MAIN.DBF          |
         4|DBF  |BOOKSHOP       |ONLINE    |    153600|              1|      288598016|         933888|/dm_home/dmdba/dmdbms/data/jydm/BOOKSHOP.DBF      |
         5|DBF  |SYSAUX         |ONLINE    |    179200|              1|      289531904|      110256128|/dm_home/dmdba/dmdbms/data/jydm/SYSAWR.DBF        |

Continue?[Y/N]:Y
restore bak_file: /dm_home/dmdba/dmdbms/backup/parallel.bak ...
start restore database...
start restore database...
start restore database...
start restore file: /dm_home/dmdba/dmdbms/data/jydm/FG_PERSON.DBF(FG_PERSON), pages: 2
start restore file: /dm_home/dmdba/dmdbms/data/jydm/DMHR.DBF(DMHR), pages: 52
start restore file: /dm_home/dmdba/dmdbms/data/jydm/SYSTEM.DBF(SYSTEM), pages: 826
end restore file: /dm_home/dmdba/dmdbms/data/jydm/FG_PERSON.DBF(FG_PERSON)
end restore database data files.

end restore file: /dm_home/dmdba/dmdbms/data/jydm/DMHR.DBF(DMHR)
end restore file: /dm_home/dmdba/dmdbms/data/jydm/SYSTEM.DBF(SYSTEM)
start restore file: /dm_home/dmdba/dmdbms/data/jydm/users01.dbf(USERS), pages: 135
start restore file: /dm_home/dmdba/dmdbms/data/jydm/ROLL.DBF(ROLL), pages: 1329
end restore file: /dm_home/dmdba/dmdbms/data/jydm/ROLL.DBF(ROLL)
end restore file: /dm_home/dmdba/dmdbms/data/jydm/users01.dbf(USERS)
start restore file: /dm_home/dmdba/dmdbms/data/jydm/MAIN.DBF(MAIN), pages: 33071
end restore database data files.

end restore file: /dm_home/dmdba/dmdbms/data/jydm/MAIN.DBF(MAIN)
start restore file: /dm_home/dmdba/dmdbms/data/jydm/BOOKSHOP.DBF(BOOKSHOP), pages: 114
end restore file: /dm_home/dmdba/dmdbms/data/jydm/BOOKSHOP.DBF(BOOKSHOP)
start restore file: /dm_home/dmdba/dmdbms/data/jydm/SYSAWR.DBF(SYSAUX), pages: 13459
end restore file: /dm_home/dmdba/dmdbms/data/jydm/SYSAWR.DBF(SYSAUX)
end restore database data files.

redo tmp arch file: /dm_home/dmdba/dmdbms/backup/RES_TMP_ARCH_20200804121936840_0.log, rpages: 16

Apply archive log LSN from 32598814 to 32598813, time used:0.000s.
restore finished, code = 0!

restore successfully!
restore time used: 9800.081(ms)

启动数据库

[root@shard1 oracle]# service DmServicejydm start
Redirecting to /bin/systemctl start  DmServicejydm.service

SQL> select * from t1;

LINEID     C1          C2
---------- ----------- -----------
1          1           1
2          2           2
3          3           3
4          4           4
5          5           5
6          6           6

6 rows got

used time: 0.427(ms). Execute id is 101.

Oracle索引访问路径因没有新的统计信息而改变

索引访问路径因没有新的统计信息而改变
在生产环境中,同一个查询的执行路径经常变化,甚至在没有任何相关变化的情况下也是如此。你确认没有收集新的统计信息(事实上,你甚至可能已经锁定了统计信息,以防止执行计划的变化)。在Oracle Database 11g之前的版本中,基数据反馈功能和自动查询调优功能,如果没有任何东西真正改变(即统计信息,实例参数等),对目前直方图的绑定窥视之类的东西没有起作用,那么执行计划几乎保持不变。然而,尽管你绝对肯定优化器不应该改变任何的执行计划,但它确实改变了。这怎么可能呢,嗯,大多数数据库都是“活体”,由于不断进行的交易数据而不断变化。事实上,如果基础数据发生了重大修改,但没有收集新的统计信息以反映这些变化,因为优化器根据不同访问路径的成本做出决定,而成本可能因为数据的变化而改变,所以执行可能将改变。

如果不随着数据的变化对优化器统计信息进行更新,在某些情况下,优化器将很可能错误地估计基数,也就是预期查询返回的行数。如果应用程序往表中添加了大量数据,而没有收集新的统计信息,你可能会认为,因为优化器不知道有新的数据,所以它会继续使用原来的执行计划(计划目前有效)。实际上,如果基于成本的优化器算错了查询真正的选择性和基数,那么随首时间的推移,它有时会改变其执行计划。在输入数量非常大的新数据后,为了执行相同的查询,优化器可能使用不同的计划,因为它低估了查询现在将检索的行数。如果在加入大量的数据之前,全表扫描是最优策略,那么在加入另外的数据后,优化器可能误以为使用索引效果会更好,而实际上全表扫描可能仍然是最好的方法。

1 使用不等条件
使用不等条件的语句,比如select * from emp where department_id<>10有时可能会导致优化器不使用索引。原因是如果优化器猜测某个查询将从表中选择大多数的值,它往往就不会使用索引。如果是这种情况,对表执行全表扫描可能是更有效的。通常情况下,优化器使用公式(1-(1/num_distinct))* num_rows估算基数。换句话说,如果某个列有1000行,其中不同的值有4个,那么基数为750。我们假设,表中大部分行满足为不等条件指定的值。在这种情况下,你可能会认为优化器会使用索引扫描,因为,毕竟所要检索的是不包含在不等条件中指定的值的所有行。然而,在指定<>操作符时,优化器会简单地忽略任何可能有的索引,即使数据分布不均,且<>条件将导致检索表中很小一部分行也是如此。在这种情况下,优化器只是倾向于执行全表扫描,而不是”正确“地选择索引。

运行这个例子中的查询,结果如下:

SQL> select * from emp where department_id<>10;

105 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |   105 |  7245 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMP  |   105 |  7245 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("DEPARTMENT_ID"<>10)

<>子句导致优化器跳过department_id列上的索引。可以尝试用index提供示强制使用索引,如下所示:

SQL> select /*+ index(emp,dept_idx) */ * from emp where department_id<>10;

105 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 169023637

------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |          |   105 |  7245 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| EMP      |   105 |  7245 |     2   (0)| 00:00:01 |
|*  2 |   INDEX FULL SCAN                   | DEPT_IDX |   104 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("DEPARTMENT_ID"<>10)

index提示使优化器用全索引扫描替换了全表扫描,虽然这是较好的,但不如索引范围扫描那么好。全索引扫描必须读取包含<>操作符中指定的值的所有叶节点,因此它不是非常有效的方法。(然而,在其他情况下,优化器可能会因为指定index提示而执行索引范围扫描。)指定<>条件的问题是,优化器甚至可能在查询返回表中很小一部分行时也跳过索引,它只是忽略where谓词中出现的列的索引。忽略索引意味着优化器在生成”最优“的计划之前,甚至不会计算索引扫描的成本,它认为这样会节省所有因此(计算索引扫描成本)花费的开销,因为它假设<>条件将导致提取表中很大一部分行。在这样的情况下,可以尝试重写查询以避免使用<>运算符。

注意:无法强制数据库执行并行索引范围扫描。但是,数据库在执行燕行嵌套循环连接时,确实执行了并行索引查找。

这里的唯一选择就是重写查询,以消除不等于子句。如果有多个谓词需要处理,就更有必要这么做。请记住,当指定not in子句时,优化器的行为与指定不等于子句是相同的。在某些情况下,另一个很好的解决方案是用case结构取代不等于谓词。请记住,如果使用case结构,那么还需要与之相匹配的基于函数的索引。

2 使用通配符查询
如果执行一个包含前导通配符搜索的查询,优化器可能会忽略索引而执行全表扫描。例如对于下面的查询:

SQL> select * from emp where last_name like '%hen';

如果匹配模式中的前导字符不是”%“或下划线(_),优化器更有可能使用索引。like运算符的初始字符使用通配符”%“或”_”,意味着数据库可能必须读取表中大部分行。如果使用索引,也需要访问每个索引块,对索引的读取完成后,可能还需要扫描大多数的表块。在这种情况下,全表扫描可能会更有效。优化器跳过last_name列的索引,因为它必须检查列中的每个值,以确定这些值是否以”hen”值结束。它最后选择了全表扫描,如下面语句的解释计划所示:

SQL> select * from emp where last_name like '%hen';


Execution Plan
----------------------------------------------------------
Plan hash value: 3956160932

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     5 |   345 |     3   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| EMP  |     5 |   345 |     3   (0)| 00:00:01 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("LAST_NAME" LIKE '%hen')

如果把上述语句修改为如下所示的语句,优化器就选择了索引扫描。

SQL> select * from emp where last_name like 'hen%';

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 2522206107

-----------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |               |     1 |    69 |     1   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| EMP           |     1 |    69 |     1   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | EMP_LAST_NAME |     1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("LAST_NAME" LIKE 'hen%')
       filter("LAST_NAME" LIKE 'hen%')

请注意,第一个例子使用前导通配符搜索。事实上,为了强制使用索引,在这个例子中,只要把通配符(%)从前导位置向后移动哪怕一个字符的位置(select * from emp where last_name like ‘h%en%),都会使用优化器使用emp表中的emp_last_name索引。我们经常使用这个例子演示,在搜索字符串中推迟使用通配符不会阻止使用索引。那么,在“%”前有多少字符就将允许使用该索引呢?当额外的字符被添加到搜索字符串中通配符(%)规范前时,优化器自然会预计该数据库将读取更少的索引和表中更少的行,因此它更倾向于选择使用索引。因此,如果搜索“ABC%”,而不是“%ABC”,那么数据库将更有可能使用索引范围扫描,因为它意识到,这时采用全表扫描的成本更高。

3 在谓词中引用空值
假设有个只有两列的表,这两列都允许NULL值。我们还假设,事实上,表中有几行在两列中都是NULL。如果执行以下语句:

SQL> select * from mytable where a is null;

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 1015944200

-----------------------------------------------------------------------------
| Id  | Operation         | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |         |     1 |    26 |     2   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| MYTABLE |     1 |    26 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("A" IS NULL)

数据库的优化器将不会使用此表上的唯一索引,因为假设有一行数据,它的某个唯一索引的所有列都是NULL值,数据库允许把这样的行添加到表中,但不会把它包括在索引中。事实上,即使表上有唯一索引,也可以向表中添加所有列都是NULL值的多少行,因为Oracle数据库认为所有列都是NULL值的两行是不同的,所以认为它们仍然符合唯一性。其结果是该表将比索引有更多的行,因为所有列都是NULL值的行不会被插入到索引中。当执行先前的查询时,数据库忽略了索引,因为该索引不包括所有的列都是NULL值的行。为了避免得出错误的答案,该数据库忽略了索引。

在这个例子中,让数据库使用索引的唯一方法是,确保在此表的两列中至少有一列被定义为

SQL> create table mytab1(a int,b int not null);

Table created.

SQL> create unique index mytab1_idx on mytab1(a,b);

Index created.

SQL> select * from mytab1 where a is null;

no rows selected


Execution Plan
----------------------------------------------------------
Plan hash value: 3315145109

-------------------------------------------------------------------------------
| Id  | Operation        | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |            |     1 |    26 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| MYTAB1_IDX |     1 |    26 |     1   (0)| 00:00:01 |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - access("A" IS NULL)

如果某行所有的索引列都是空的,Oracle数据库就不会把该行包含到索引中。然而,实际上可以简单地增加另一列到索引中,对NULL值进行索引,
如下所示:

SQL>create index with_null on employees(nullable_column,'1');

4 在查询中包含函数
如果某个查询在where子句中包含索引列上的函数,优化器也会跳过索引。请注意,无论是你在查询中显式地应用了函数,还是数据库在你不知道的情况下隐式地应用了函数,优化器都会跳过索引。下面先讨论显式应用函数。比如,执行以下查询:

SQL>select * from emp where upper(last_name)='CHEN';

在这种情况下,由于upper函数的存在,优化器跳过了last_name列的索引。(第5章介绍了如何使用基于函数的索引来解决这个问题)。如果应用程序需要频繁地把函数应用于索引列,那么最好创建基于函数的索引,以便允许数据库使用索引。

请注意,即使查询没有显式地把函数应用到某个列,在某些情况下它也可能隐式地这样做。例如,如果在表中定义了一个数值型的列,然后通过指定一个字符,而不是一个数值来查询列值,优化器就会忽略索引。也就是说,如果执行语句select * from emp where department_id=’10’,而不是select * from emp where department_id=10,优化器需要在幕后应用to_number函数才能得到答案。再次强调,使用函数意味着优化器将不使用索引。在这种情况下,即使指定了index提示,优化器也可能会执行全索引扫描,但不会执行索引唯一扫描。因为全索引扫描必须扫描整个索引,所以它比索引唯一扫描慢得多。

日期型数据经常会引起隐式转换,从而阻止使用索引。下面的表达式是非常常见的:

SQL> select * from emp where trunc(hire_date)=trunc(sysdate);

在写这样的查询时,人们往往下意识地使用trunc函数。我们把包含时间的日期截断,以消除一天中的时间,往往不考虑查询执行的后果。然而,对Oracle数据库而言,它只是注意到并没有真正对表达式trunc(hire_date)进行索引,而只索引了hire_date列。因此,数据库忽略了索引。

列trunc(hire_date)上的基于函数的索引会使优化器选择访问索引,但还有一种更简单的方法可以解决这个问题,而无需创建基于函数的索引。

只要对sysdate值使用trunc函数,并把等于运算符替换为范围比较运算符(大于或小于),就可以不必在hire_date列上应用trunc函数。也就是说,对于如下的语句:

select * from emp where trunc(hire_date)=trunc(sysdate);

可把它改写为下面这个语句:

select * from emp where hire_date>=trunc(sysdate) and hire_date

因为对索引列hire_date移除了trunc函数,所以优化器会使用该列上的索引。

5 跳过索引的前导部分
如果在两个或多个列上有一个复合索引,但没有在查询中使用索引的前导部分,那么优化器很可能会忽略表上的索引,而执行全表扫描。比如,在表mytab1的列(a,b)上有一个索引,a是前导列。如果执行select * from mytab1 where b=99这样的SQL语句,数据库会忽略列(a,b)上的索引,因为它必须在表中的每个单独索引项上检查列a所有可能的值。

请注意,如果执行select a,b from mytab1这样的查询语句,优化器更可能使用(a,b)上的索引,因为它意识到这两列都是索引的一部分。因为索引比表更紧凑,而且数据库可以从索引本身得到查询所请求的所有值,所以优化器可能会执行索引快速全扫描。

即使某个查询不含索引的前导部分,但如果一个复合索引的前导列的不同值很少,数据库仍然可以使用索引。在这种情况下,该数据库将执行索引跳跃式扫描,如在第5章中所解释的那样。

在优化器选择了跳跃式扫描时,在谓词中使用的列前可以有多个前导的索引列。我们所见过的案例中,有谓词列前多达6列的情况,优化器仍然采用了跳跃式扫描。数据库管理员往往认为只有前导列值的个数少时,跳跃扫描才是可行的,但“少”是相对的。如果优化器认为跳跃式扫描比全表扫描的成本更低,那么优化器就将选择跳跃式扫描,最终,成本估算起着决定作用并主导优化器的选择。

Oracle优化器忽略索引的原因

优化器忽略索引的原因
创建索引永远不能保证优化器在评估执行计划时一定会使用索引。如果某个查询从表中选择高比例的行,优化器可能觉得使用全表扫描而不是索引扫描,能更快地得到结果。请记住,数据库使用索引时,它首先查找索引获得rowid,然后使用这些rowid来检索所请求的行。如果查询从表中选择很大比例的行,从而导致要读取表中很大比例的块,那么数据库可能执行全表扫描来避免既读取索引又读取表,因为后者的成本可能比仅仅扫描一次表更高。

优化器是否使用索引取决于多种因素,在本章以下各节将分别对它们进行解释。

1 不同的行数
选择全表扫描或索引扫描的另一关键决定因素是,表中与给定查询谓词相匹配的不同行数占表中总行数的比率。通过查询dba_tables视图的num_rows列可以得到某个表的行数。同样,也可以通过查询dba_tab_columns视图的num_distinct列,得到任意列中不同值的数量。num_rows列与num_distinct列的值越接近,优化器越有可能倾向于访问该列的索引而非执行全表扫描,换句话说,索引的选择性越高,数据库就越有可能使用它。

索引的选择性可能会对数据库是否使用索引产生最大的影响。选择性是指每个列值有多少个不同的值。如果索引是非常有选择性的,那么每个索引条目只有很少几行。另外,如果索引的选择性不强,每个索引条目就会有许多行。

请记住,优化器用列的选择性乘以页块(leaf blocks)的统计数量,来估算在访问索引期间,数据库必须读取多少个索引块。虽然事实上,大多数情况下,高选择性的列确实会使用索引,但并不总是如此,因为使用索引还是全表扫描的最终决定因素是块的选择性。

在Oracle Database 10g版本(但不是在11g版本)中,使用dbms_stats.auto_sample_size常量估计dbms_stats包使用的行数,可能会导致对不同值的数量(NDV)产生错误的估计。如果表很大,而且有相当数量的数据是偏态的,往往就会发生这种情况。因此最好对样本大小使用自己的估计,以获得更准确的NDV值。

2 索引聚簇因子
查询dba_indexes视图的clustering_factor列,可以找到索引的聚簇因子的值。聚簇因子用来衡量表中行的有序程度,这种有序程度是与索引的行相比较而言的。如果聚簇因子接近表中的行数,行就有可能是非常随机地排列的,这种情况下,一个索引块的索引条目对应的数据行不太可能位于相同的数据块中。表的选择性(通过过滤)乘以索引聚簇因子,决定了通过索引访问表的成本。这部分计算中使用的实际上是表的选择性。虽然大部分时间,索引的选择性(乘以leaf_blocks,已在上一节讨论)和表的选择性是相同的,计算它实际上是为了确定需要访问表中的多少数据块。通常情况下,我们都假定索引聚簇因子能保证随机性,但事实并非如此。例如,虽然索引中的每行只指向两个不同的块,但条目是按rowid排序为块1,块2,块1,块2……这种(交替排列的)情况会怎么样呢? 如果索引有10000个条目,聚簇因子是10000,但实际上,将仅访问2个块。因此,聚簇因子的计算不能像大多数人认为的那样,保证数据排列的随机性。

在一个具有“好”的聚簇因子的索引中,具体索引叶块中的索引值指向分布在相同数据块中的行。另一方面,在一个具有“坏”的聚簇因子,它可以用更少的I/O读取数据。而具有相同数量的数据但组织得很差的索引,将需要更大的I/O数量,从一组更多的数据块中读取数据。在这种情况下,关键是要注意,如果每个表只有一个索引,那么它的组织可能是理想的,实际上,这只有在表中的数据按特定的顺序加载时才真正成立。举例来说,或许表是按order_date列的顺序加载的。在这种情况下,order_date上索引的聚簇因子将和表中块的数量几乎相同。但是,因为该表的存储只能按一种顺序排列,所以其他所有索引的顺序都将是“欠优化”的。因此,总而言之,“好”与“坏”更是相对而不是绝对的。这可能就是为什么使用索引的成本计算,由包括表和索引选择性的多个元素组成,以使某一个组成部分不会占非常大的比重。

一条经验法则是:良好的聚簇因子接近表的块数,而糟糕的聚簇因子接近表的行数。

除了这里讨论的两个因素,多块读取数的值对索引使用也有影响。数据库文件多块读取计数(db_file_multiblock_read_count)的值越高,从优化器的角度来看,全表扫描的成本就越低。