热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

Oracle中行迁移和行链接的清除及检测

一、行迁移和行链接的介绍在实际的工作中我们经常会碰到一些Oracle数据库性能较低的问题,当然,引起Oracle数据库性能较低的原因是多方面的,我们能够通过一些正确的设计和诊断来尽量的避免一些Oracle数据库性能不好,RowMigration(行迁移)RowChaining

一、行迁移和行链接的介绍 在实际的工作中我们经常会碰到一些Oracle数据库性能较低的问题,当然,引起Oracle数据库性能较低的原因是多方面的,我们能够通过一些正确的设计和诊断来尽量的避免一些Oracle数据库性能不好,Row Migration (行迁移) Row Chaining


一、行迁移和行链接的介绍  

在实际的工作中我们经常会碰到一些Oracle数据库性能较低的问题,当然,引起Oracle数据库性能较低的原因是多方面的,我们能够通过一些正确的设计和诊断来尽量的避免一些Oracle数据库性能不好,Row Migration (行迁移) & Row Chaining (行链接)就是其中我们可以尽量避免的引起Oracle数据库性能低下的潜在问题。通过合理的诊断行迁移和行链接,我们可以较大幅度上提高Oracle数据库的性能。

那究竟什么是行迁移和行链接呢,先让我们从Oracle的block开始谈起。

操作系统的最小读写操作单元是操作系统的block,所以当创建一个Oracle数据库的时候我们应该讲数据库的block size设置成为操作系统的block size的整数倍,Oracle block是Oracle数据库中读写操作的最小单元,Oracle9i之前的Oracle数据库版本中Oracle block一旦在创建数据库的时候被设定后就没法再更改。为了在创建数据库之前确定一个合理的Oracle block的大小,我们需要考虑一些因素,例如数据库本身的大小以及并发事务的数量等。使用一个合适的Oracle block大小对于数据库的调优是非常重要的。

一个Oracle block由三个部分组成,分别是数据块头、自由空间、实际数据三部份组成。

数据块头:主要包含有数据块地址的一些基本信息和段的类型,以及表和包含有数据的实际行的地址。

自由空间:是指可以为以后的更新和插入操作分配的空间,大小由PCTFREE和PCTUSED两个参数影响。

实际数据:是指在行内存储的实际数据。

当创建或者更改任何表和索引的时候,Oracle在空间控制方面使用两个存储参数:

PCTFREE:为将来更新已经存在的数据预留空间的百分比。

PCTUSED:用于为插入一新行数据的最小空间的百分比。这个值决定了块的可用状态。可用的块时可以执行插入的块,不可用状态的块只能执行删除和修改,可用状态的块被放在freelist中。

当表中一行的数据不能在一个数据block中放入的时候,这个时候就会发生两种情况,一种是行链接,另外一种就是行迁移了。

行链接产生在第一次插入数据的时候如果一个block不能存放一行记录的情况下。这种情况下,Oracle将使用链接一个或者多个在这个段中保留的block存储这一行记录,行链接比较容易发生在比较大的行上,例如行上有LONG、LONG RAW、LOB等数据类型的字段,这种时候行链接是不可避免的会产生的。

当一行记录初始插入的时候事可以存储在一个block中的,由于更新操作导致行长增加了,而block的自由空间已经完全满了,这个时候就产生了行迁移。在这种情况下,Oracle将会迁移整行数据到一个新的block中(假设一个block中可以存储下整行数据),Oracle会保留被迁移行的原始指针指向新的存放行数据的block,这就意味着被迁移行的ROW ID是不会改变的。

当发生了行迁移或者行链接,对这行数据操作的性能就会降低,因为Oracle必须要扫描更多的block来获得这行的信息。

下面举例来具体说明行迁移和行链接的产生过程。

先创建一个pctfree为20和pctused为50的测试表:

create table test(

col1 char(20),

col2 number)

storage (

pctfree 20

pctused 50);

当插入一条记录的时候,Oracle会在free list中先去寻找一个自由的块,并且将数据插入到这个自由块中。而在free list中存在的自由的块是由pctfree值决定的。初始的空块都是在free list中的,直到块中的自由空间达到pctfree的值,此块就会从free list中移走,而当此块中的使用空间低于pctused的时候,此块又被重新放到free list中。

Oracle使用free list机制可以大大的提高性能,对于每次的插入操作,Oracle只需要查找free list就可以了,而不是去查找所有的block来寻找自由空间。

具体我们通过下面的一个试验来查看行链接和行迁移是如何产生并在数据文件中体现出来的。先查看ALLAN这个表空间的数据文件号,为了便于测试,我只建立了一个数据文件。

SQL> select file_id from dba_data_files where tablespace_name='ALLAN';

FILE_ID

----------

23

创建一个测试表test:

SQL> create table test ( x int primary key, 
a char(2000), b char(2000), c char(2000), 
d char(2000), e char(2000) ) tablespace allan;

Table created.

因为我的数据库的db_block_size是8K,所以我创建的表有五个字段,每个占2000个字节,这样一行记录大约10K,就能超过一个block的大小了。

然后插入一行记录,只有一个字段的:

SQL> insert into test(x) values (1);

1 row created.

SQL> commit;

Commit complete.

查找这行记录所在的block,并dump出来:

SQL> select dbms_rowid.rowid_block_number(rowid) from test;

DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)

34

SQL> alter system dump datafile 23 block 34;

System altered.

在udump目录下查看trace文件的内容如下:

Start dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34

buffer tsn: 34 rdba: 0x05c00022 (23/34)

scn: 0x0000.013943f3 seq: 0x01 flg: 0x02 tail: 0x43f30601

frmt: 0x02 chkval: 0x0000 type: 0x06=trans data

Block header dump: 0x05c00022

Object id on Block? Y

seg/obj: 0x3ccd csc: 0x00.13943ef itc: 2 flg: O typ: 1 - DATA

fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc

0x01 0x000a.02e.00000ad7 0x00800036.03de.18 --U- 1 fsc 0x0000.013943f3

0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000

data_block_dump,data header at 0xadb505c

tsiz: 0x1fa0

hsiz: 0x14

pbl: 0x0adb505c

bdba: 0x05c00022

76543210

flag=--------

ntab=1

nrow=1

frre=-1

fsbo=0x14

fseo=0x1f9a

avsp=0x1f83

tosp=0x1f83
0xe:pti[0] nrow=1 offs=0

0x12:pri[0] offs=0x1f9a

block_row_dump:

tab 0, row 0, @0x1f9a

tl: 6 fb: --H-FL-- lb: 0x1 cc: 1

col 0: [ 2] c1 02

end_of_block_dump

End dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34

对其中的一些信息做一些解释:

Fb:H是指行记录的头,L是指行记录的最后一列,F是指行记录的第一列。

Cc:列的数量。

Nrid:对于行链接或者行迁移来说的下一个row id的值。

由上面的dump信息我们可以看出来当前表test是没有行链接或者行迁移的。

然后更新test表,并重新dump出来:

SQL> update test set a='test',b='test',c='test',d='test',e='test' where x=1;

1 row updated.

SQL> commit;

Commit complete.

此时应该有行迁移和行链接产生了。

SQL> alter system dump datafile 23 block 34;

System altered.

在udump目录下查看trace文件的内容如下:

Start dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34

buffer tsn: 34 rdba: 0x05c00022 (23/34)

scn: 0x0000.0139442b seq: 0x01 flg: 0x02 tail: 0x442b0601

frmt: 0x02 chkval: 0x0000 type: 0x06=trans data

Block header dump: 0x05c00022

Object id on Block? Y

seg/obj: 0x3ccd csc: 0x00.1394429 itc: 2 flg: - typ: 1 - DATA

fsl: 0 fnx: 0x0 ver: 0x01

Itl Xid Uba Flag Lck Scn/Fsc

0x01 0x000a.02e.00000ad7 0x00800036.03de.18 C--- 0 scn 0x0000.013943f3

0x02 0x0004.002.00000ae0 0x0080003b.0441.11 --U- 1 fsc 0x0000.0139442b

data_block_dump,data header at 0xadb505c

===============

tsiz: 0x1fa0

hsiz: 0x14

pbl: 0x0adb505c

bdba: 0x05c00022

76543210

flag=--------

ntab=1

nrow=1

frre=-1

fsbo=0x14

fseo=0x178a

avsp=0x177c

tosp=0x177c

0xe:pti[0] nrow=1 offs=0

0x12:pri[0] offs=0x178a

block_row_dump:

tab 0, row 0, @0x178a

tl: 2064 fb: --H-F--N lb: 0x2 cc: 3

nrid: 0x05c00023.0

col 0: [ 2] c1 02

col 1: [2000]

74 65 73 74 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20

20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20

…………

col 2: [48]

74 65 73 74 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20

20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20

end_of_block_dump

End dump data blocks tsn: 34 file#: 23 minblk 34 maxblk 34

我们不难看出,nrid出现了值,指向了下一个row id,证明刚刚的update操作使这行记录产生了行链接或者行?

二、行迁移和行链接的检测

通过前面的介绍我们知道,行链接主要是由于数据库的db_block_size不够大,对于一些大的字段没法在一个block中存储下,从而产生了行链接。对于行链接我们除了增大db_block_size之外没有别的任何办法去避免,但是因为数据库建立后db_block_size是不可改变的(在9i之前),对于Oracle9i的数据库我们可以对不同的表空间指定不同的db_block_size,因此行链接的产生几乎是不可避免的,也没有太多可以调整的地方。行迁移则主要是由于更新表的时候,由于表的pctfree参数设置太小,导致block中没有足够的空间去容纳更新后的记录,从而产生了行迁移。对于行迁移来说就非常有调整的必要了,因为这个是可以调整和控制清除的。

如何检测数据库中存在有了行迁移和行链接呢?我们可以利用Oracle数据库自身提供的脚本utlchain.sql(在$ORACLE_HOME/rdbms/admin目录下)生成chained_rows表,然后利用ANALYZE TABLE table_name LIST CHAINED ROWS INTO chained_rows命令逐个分析表,将分析的结果存入chained_rows表中。从utlchain.sql脚本中我们看到chained_rows的建表脚本,对于分区表,cluster表都是适用的。然后可以使用拼凑语句的办法生成分析所需要的表的脚本,并执行脚本将具体的分析数据放入Chained_rows表中,例如下面是分析一个用户下所有表的脚本:

SPOOL list_migation_rows.sql

SET ECHO OFF

SET HEADING OFF

SELECT 'ANALYZE TABLE ' || table_name ||
 ' LIST CHAINED ROWS INTO chained_rows;' FROM user_tables;

SPOOL OFF

然后查询chained_rows表,可以具体查看某张表上有多少的行链接和行迁移。

SELECT table_name, count(*) from chained_rows GROUP BY table_name;

当然,也可以查询v$sysstat视图中的’table fetch continued row’列得到当前的行链接和行迁移数量。

SELECT name, value FROM v$sysstat WHERE name = 'table fetch continued row';

可以使用如下的脚本来直接查找存在有行链接和行迁移的表,自动完成所有的分析和统计。

accept owner prompt " Enter the schema name 
to check for Row Chaining (RETURN for All): "
prompt
prompt
accept table prompt " Enter the table name 
to check (RETURN for All tables owned by &owner): "
prompt
prompt
set head off serverout on term on feed off veri off echo off
!clear
prompt 
declare
v_owner varchar2(30);
v_table varchar2(30);
v_chains number;
v_rows number;
v_count number := 0;
sql_stmt varchar2(100);
dynamicCursor INTEGER;
dummy INTEGER;
cursor chains is
select count(*) from chained_rows;
cursor analyze is
select owner, table_name
from sys.dba_tables 
where owner like upper('%&owner%')
and table_name like upper('%&table%')
order by table_name;
begin
dbms_output.enable(64000);
open analyze;
fetch analyze into v_owner, v_table;
while analyze%FOUND loop
dynamicCursor := dbms_sql.open_cursor;
sql_stmt := 'analyze table '||v_owner
||'.'||v_table||' list chained rows into chained_rows';
dbms_sql.parse(dynamicCursor, sql_stmt, dbms_sql.native);
dummy := dbms_sql.execute(dynamicCursor);
dbms_sql.close_cursor(dynamicCursor);
open chains;
fetch chains into v_chains;
if (v_chains != 0) then
if (v_count = 0) then
dbms_output.put_line(CHR(9)||CHR(9)||CHR(9)
||'<<<<>>>>');
v_count := 1;
end if;
dynamicCursor := dbms_sql.open_cursor;
sql_stmt := 'Select count(*) v_rows'||' From '||v_owner||'.'||v_table;
dbms_sql.parse(dynamicCursor, sql_stmt, dbms_sql.native);
dbms_sql.DEFINE_COLUMN(dynamicCursor, 1, v_rows);
dummy := dbms_sql.execute(dynamicCursor);
dummy := dbms_sql.fetch_rows(dynamicCursor);
dbms_sql.COLUMN_VALUE(dynamicCursor, 1, v_rows);
dbms_sql.close_cursor(dynamicCursor);
dbms_output.put_line(v_owner||'.'||v_table);
dbms_output.put_line(CHR(9)||'---> Has '
||v_chains||' Chained Rows and '||v_rows||' Num_Rows in it!');
dynamicCursor := dbms_sql.open_cursor;
sql_stmt := 'truncate table chained_rows';
dbms_sql.parse(dynamicCursor, sql_stmt, dbms_sql.native);
dummy := dbms_sql.execute(dynamicCursor);
dbms_sql.close_cursor(dynamicCursor);
v_chains := 0;
end if;
close chains;
fetch analyze into v_owner, v_table;
end loop;
if (v_count = 0) then
dbms_output.put_line('No Chained Rows found 
in the '||v_owner||' owned Tables!');
end if;
close analyze;
end;
/
set feed on head on
prompt

三、行迁移和行链接的清除

由于对于行链接来说只能增大db_block_size来清除,而db_block_size在创建了数据库后又是不能改变了的,所以这里对行链接的清除不做过多的叙述了,主要是针对行迁移来谈谈在实际的生产系统中如何去清除。

对于行迁移的清除,一般来说分为两个步骤:第一步,控制住行迁移的增长,使其不在增多;第二步,清除掉以前存在的行迁移。

众所周知,行迁移产生的主要原因是因为表上的pctfree参数设置过小导致的,而要实现第一步控制住行迁移的增长,就必须设置好一个正确合适的pctfree参数,否则即使清除了当前的行迁移后马上又会产生很多新的行迁移。当然,这个参数也不是越大越好的,如果pctfree设置的过大,会导致数据块的利用率低,造成空间的大量浪费,因此必须设置一个合理的pctfree参数。如何去确定一个表上合理的pctfree参数呢,一般来说有两种方法。

第一种是定量的的设定方法,就是利用公式来设定pctfree的大小。先使用ANALYZE TABLE table_name ESTIMATE STATISTICS命令来分析要修改pctfree的表,然后查看user_tables中的AVG_ROW_LEN列&#20540;,得到一个平均行长AVG_ROW_LEN1,然后大量的对表操作之后,再次使用上述命令分析表,得到第二个平均行长AVG_ROW_LEN2,然后运用公式100 * (AVG_ROW_LEN2-AVG_ROW_LEN1)/(AVG_ROW_LEN2-AVG_ROW_LEN1 &#43; 原始的AVG_ROW_LEN)得出的结果就是定量计算出来的一个合适的pctfree的&#20540;。这种方法因为是定量计算出来的,可能不一定会很准确,而且因为要分析表,所以对于使用RBO执行计划的系统不是很适用。例如:avg_row_len_1 = 60,avg_row_len_2 = 70,则平均修改量为 10,PCTFREE 应调整为 100 * 10 /(10 &#43; 60)= 16.7% 。

第二种是差分微调的方法,先查询到当前表的pctfree的&#20540;,然后监控和调整pctfree参数,每次增加一点pctfree的大小,每次增加的比例不要超过5个百分点,然后使用ANALYZE TABLE TABLE_NAME LIST CHAINED ROWS INTO chained_rows命令分析每次所有的行迁移和行链接的增长情况,对于不同的表采取不同的增长比例,对于行迁移增长的比较快的表pctfree&#20540;就增加的多点,对于增长慢的表就增加的少点,直到表的行迁移基本保持不增长了为止。但是注意不要把pctfree调的过大,一般在40%以下就可以了,否则会造成空间的很大浪费和增加数据库访问的IO。

使用上述的方法控制住了当前表的行迁移的增长之后,就可以开始清除之前表上存在的行迁移了。是否清除掉行迁移,关系到系统的性能是否能够有很大的提高。因此,对于以前存在的行迁移是一定而且必须要清除掉的。清除掉已经存在的行迁移有很多方法,但是并不是所有的方法都能适用所有的情况,例如表中的记录数多少,表上的关联多少、表上行迁移的数量多少等等这些因素都会是成为制约你使用什么方法清除的条件,因此,根据表的特点和具体情况的不同我们应该采用不同的方法去清除行迁移。下面我将逐一介绍各种清除行迁移的方法以及它们各自适用的不同情况。

方法一:传统的清除行迁移的方法

具体步骤如下:

1. 执行$ORACLE_HOME/rdbms/admin目录下的utlchain.sql脚本创建chained_rows表。

@$ORACLE_HOME/rdbms/admin/utlchain.sql

2. 将存在有行迁移的表(用table_name代替)中的产生行迁移的行的rowid放入到chained_rows表中。

ANALYZE TABLE table_name LIST CHAINED ROWS INTO chained_rows;

3. 将表中的行迁移的row id放入临时表中保存。

CREATE TABLE table_name_temp AS

SELECT * FROM table_name

WHERE rowid IN

(SELECT head_rowid FROM chained_rows

WHERE table_name = 'table_name');

4. 删除原来表中存在的行迁移的记录行。

DELETE table_name

WHERE rowid IN

(SELECT head_rowid

FROM chained_rows

WHERE table_name = 'table_name');

5. 从临时表中取出并重新插入那些被删除了的数据到原来的表中,并删除临时表。

INSERT INTO table_name SELECT * FROM table_name_temp;

DROP TABLE table_name_temp;

对于这种传统的清除RM的方法,优点是执行起来过程比较简单,容易实现。但是这种算法的缺陷是没有考虑到表关联的情况,在大多数数据库中很多表都是和别的表之间有表关联的,有外键的限制,这样就造成在步骤3中根本无法delete掉存在有行迁移的记录行,所以这种方法能够适用的表的范围是有限的,只能适用于表上无任何外键关联的表。由于这种方法在插入和删除数据的时候都没有disable掉索引,这样导致主要消耗时间是在删除和插入时维持索引树的均衡上了,这个对于如果记录数不多的情况时间上还比较短,但是如果对于记录数很多的表这个所消耗的时间就不是能够接受的了。显然,这种方法在处理大数据量的表的时候显然是不可取的。

以下是一个具体在生产数据库上清除行迁移的例子,在这之前已经调整过表的pctfree参数至一个合适的&#20540;了:

SQL>@$ORACLE_HOME/rdbms/admin/utlchain.sql

Table created.

SQL> ANALYZE TABLE CUSTOMER LIST CHAINED ROWS INTO chained_rows;

Table analyzed.

SQL>SELECT count(*) from chained_rows;

TABLE_NAME COUNT(*)

CUSTOMER 21306

1 rows selected.

查看在CUSTOMER表上存在的限制:

SQL>select CONSTRAINT_NAME,CONSTRAINT_TYPE,
TABLE_NAME from USER_CONSTRAINTS where TABLE_NAME='CUSTOMER';

CONSTRAINT_NAME C TABLE_NAME

------------------------------ - --

PK_CUSTOMER1 P CUSTOMER

SQL>select CONSTRAINT_NAME,CONSTRAINT_TYPE,
TABLE_NAME from USER_CONSTRAINTS 
where R_CONSTRAINT_NAME='PK_CUSTOMER1';

no rows selected

SQL> CREATE TABLE CUSTOMER_temp AS

SELECT * FROM CUSTOMER WHERE rowid IN

(SELECT head_rowid FROM chained_rows

WHERE table_name = 'CUSTOMER'); 

Table created.

SQL>select count(*) from CUSTOMER;

COUNT(*)

----------

338299

SQL> DELETE CUSTOMER WHERE rowid IN

(SELECT head_rowid

FROM chained_rows

WHERE table_name = 'CUSTOMER');

21306 rows deleted.

SQL> INSERT INTO CUSTOMER SELECT * FROM CUSTOMER_temp;

21306 rows created.

SQL> DROP TABLE CUSTOMER_temp;

Table dropped.

SQL> commit;

Commit complete.

SQL> select count(*) from CUSTOMER;

COUNT(*)

----------

338299

SQL> truncate table chained_rows;

Table truncated.

SQL> ANALYZE TABLE CUSTOMER LIST CHAINED ROWS INTO chained_rows;

Table analyzed.

SQL> select count(*) from chained_rows; 

COUNT(*)

----------

0

以上整个清除两万多行的行迁移过程在三分钟左右,而且全部都在联机的状态下完成,基本上不会对业务有什么影响,唯一就是在要清除行迁移的表上不能有对外键的限制,否则就不能采用这个方法去清除了。

推荐阅读
  • MySQL的查询执行流程涉及多个关键组件,包括连接器、查询缓存、分析器和优化器。在服务层,连接器负责建立与客户端的连接,查询缓存用于存储和检索常用查询结果,以提高性能。分析器则解析SQL语句,生成语法树,而优化器负责选择最优的查询执行计划。这一流程确保了MySQL能够高效地处理各种复杂的查询请求。 ... [详细]
  • 在使用达梦数据库时,管理员可能会遇到连接频繁中断或特定SQL语句语法错误的问题。这些问题通常源于开发人员在创建对象时的不规范操作。为了解决这些问题,建议对数据库配置进行优化,并确保所有SQL语句符合达梦数据库的标准语法。此外,定期检查和维护数据库连接参数,以及对异常日志进行详细分析,也有助于及时发现并解决问题。 ... [详细]
  • 本文对SQL Server系统进行了基本概述,并深入解析了其核心功能。SQL Server不仅提供了强大的数据存储和管理能力,还支持复杂的查询操作和事务处理。通过MyEclipse、SQL Server和Tomcat的集成开发环境,可以高效地构建银行转账系统。在实现过程中,需要确保表单参数与后台代码中的属性值一致,同时在Servlet中处理用户登录验证,以确保系统的安全性和可靠性。 ... [详细]
  • 本文探讨了POJ3177中的冗余路径问题,并详细介绍了如何利用Tarjan算法进行求解。通过分析图的强连通分量,Tarjan算法能够高效地识别出图中的关键路径和冗余路径,为解决复杂网络问题提供了有力工具。此外,文章还结合具体实例,深入讲解了算法的应用步骤和实现细节,帮助读者更好地理解和掌握这一重要算法。 ... [详细]
  • XAMPP 遇到 404 错误:无法找到请求的对象
    在使用 XAMPP 时遇到 404 错误,表示请求的对象未找到。通过详细分析发现,该问题可能由以下原因引起:1. `httpd-vhosts.conf` 文件中的配置路径错误;2. `public` 目录下缺少 `.htaccess` 文件。建议检查并修正这些配置,以确保服务器能够正确识别和访问所需的文件路径。 ... [详细]
  • 题目《BZOJ2654: Tree》的时间限制为30秒,内存限制为512MB。该问题通过结合二分查找和Kruskal算法,提供了一种高效的优化解决方案。具体而言,利用二分查找缩小解的范围,再通过Kruskal算法构建最小生成树,从而在复杂度上实现了显著的优化。此方法不仅提高了算法的效率,还确保了在大规模数据集上的稳定性能。 ... [详细]
  • 在Python中,利用MD5哈希算法生成密码值是一种常见的安全措施。本文详细介绍了MD5算法的基本原理及其在密码学中的应用,探讨了如何使用Python标准库中的`hashlib`模块来实现MD5哈希值的生成,并讨论了其在实际项目中的应用场景和潜在的安全风险。此外,文章还提供了代码示例,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 在 LeetCode 的“有效回文串 II”问题中,给定一个非空字符串 `s`,允许删除最多一个字符。本篇深入解析了如何判断删除一个字符后,字符串是否能成为回文串,并提出了高效的优化算法。通过详细的分析和代码实现,本文提供了多种解决方案,帮助读者更好地理解和应用这一算法。 ... [详细]
  • 深入解析国内AEB应用:摄像头和毫米波雷达融合技术的现状与前景
    本文作者程建伟,武汉极目智能技术有限公司CEO,入选武汉市“光谷3551人才计划”。文章详细探讨了国内自动紧急制动(AEB)系统中摄像头与毫米波雷达融合技术的现状及未来前景。通过分析当前技术的应用情况、存在的挑战以及潜在的解决方案,作者指出,随着传感器技术的不断进步和算法优化,AEB系统的性能将大幅提升,为交通安全带来显著改善。 ... [详细]
  • 搜索引擎技术概论(上篇):核心原理与应用分析
    搜索引擎技术概论(上篇)探讨了搜索的基本概念及其核心原理。搜索的本质在于信息检索,即用户通过输入关键词,利用特定的算法从海量数据中快速定位并提供所需信息。本文详细分析了搜索引擎的工作机制及其在实际应用中的表现。 ... [详细]
  • 本文通过思维导图的形式,深入解析了大型网站技术架构的核心原理与实际案例。首先,探讨了大型网站架构的演化过程,从单体应用到分布式系统的转变,以及各阶段的关键技术和挑战。接着,详细分析了常见的大型网站架构模式,包括负载均衡、缓存机制、数据库设计等,并结合具体案例进行说明。这些内容不仅有助于理解大型网站的技术实现,还能为实际项目提供宝贵的参考。 ... [详细]
  • ES6引入了Symbol这一新型原始数据类型,其核心特性在于能够生成独一无二的值。起初,对于“独一无二”的概念我并未完全理解,但通过查阅相关资料并结合个人见解,逐步掌握了其精髓。Symbol的独特之处不仅在于其唯一性,还在于它在编程中的多种应用场景,如防止属性名冲突等。本文将深入探讨Symbol的特性和实际应用,帮助读者全面理解这一重要特性。 ... [详细]
  • 本文提出了一种基于栈结构的高效四则运算表达式求值方法。该方法能够处理包含加、减、乘、除运算符以及十进制整数和小括号的算术表达式。通过定义和实现栈的基本操作,如入栈、出栈和判空等,算法能够准确地解析并计算输入的表达式,最终输出其计算结果。此方法不仅提高了计算效率,还增强了对复杂表达式的处理能力。 ... [详细]
  • 遗传算法中选择算子为何置于交叉算子和变异算子之前?本文探讨了这一问题,并详细介绍了遗传算法中常用的选择算子类型及其作用机制。此外,还分析了不同选择算子对算法性能的影响,为实际应用提供了理论依据。 ... [详细]
  • 非线性门控感知器算法的实现与应用分析 ... [详细]
author-avatar
1257523034_627418
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有