精华内容
下载资源
问答
  • 全面认识INFORMIX临时表

    万次阅读 2009-10-21 14:26:00
    全方位认识INFORMIX临时表临时表IDS11.5新特性概述 本文描述Informix临时表的概念、SQL、临时表空间、约束、新特性以及优化建议。目的旨在说明如何在我们的应用开发中合理的使用和管理Informix临时表。在Informix...

    全方位认识INFORMIX临时表及临时表IDS11.5新特性

    概述

           本文描述Informix临时表的概念、SQL、临时表空间、约束、新特性以及优化建议。目的旨在说明如何在我们的应用开发中合理的使用和管理Informix临时表。

    Informix数据库中,我们可以创建临时表来处理应用中的临时数据,并且临时表数据存储在临时表空间中。Informix系统不记录临时表的字典信息,从数据库系统表中查询不到临时表的如何相关信息。可以在临时表上创建索引。临时表的作用域为session,当session结束(应用程序断开数据库)、数据库实例关闭或者系统异常关闭后重新启动时临时表由数据库系统自动进行删除。因此,我们需要正确利用Informix临时表这些特点来解决我们数据库应用系统中的各种业务问题。

    临时表SQL语法

           可以采用如下两种方式创建临时表:

          A、使用 SELECT INTO TEMP 语句隐含地创建临时表;

        B、使用 CREATE TEMP TABLE 语句显示地创建临时表;

        显示的创建临时表的语法描述如下:

     

     

     

           注意事项:

    n         命名规则:临时表只作用于一个session中,而不在整个数据库中。在一个session创建临时表时应该遵守如下规则:

    A、  临时表明必须不同于当前数据库中其他table,view,sequencesynonym的名称;

    B、  可以与其他session中的临时表名称相同;

    C、  在同一session中,不能创建相同名称的临时表,可以先删除后再创建。

    n         WITH NO LOG:在日志数据库中,定义该选项后,对该临时表的操作不记录事务日志。

    示例说明:如下示例说明临时表的使用语法。

    DataBase:demodb buffed log

    数据库demodb存在如下表:tab1  create table tab1(c1 integer);

    Session 1:
    Create temp table tmp_a(c1 integer,c2 char(2)) with no log;
    Insert into table tmp_a(c1,c2) values(1,’a’);
    Create index idx_tmp_a on a(c1);
    Select * from tab1 into tmp_b with no log;
    Select c1 from tmp_a into tmp_c with no log;
    Drop table tmp_a;
    Create temp table tmp_a(c1 int) with no log;

    Session 2:
    Create temp table tmp_a(c1 integer,c2 char) with no log;
    Insert into tmp_a(c1) values (3);
    Select * from tmp_a into tab1 with no log;
    --Error: tab1名称与数据库已有表tab1冲突
    create temp table tmp_a(t1 integer);
    --Error:临时表表名tmp_a在该session中已经创建

    系统创建的临时表

    在如下几种情形下,数据库服务器将自动创建临时表。

    n         使用GROUP BY ORDER BY 子句;

    n         包含聚集函数,并且使用了UNIQUE或者DISTINCT

    n         执行计划使用HASH JOIN的表关联;

    n         复杂的CREATE VIEW;

    n         创建scroll cursor

    n         关联子查询;

    n         应用IN或者ANY子句的子查询;

    n         创建INDEX

    临时表的存储

    如果数据库采用非日志模式,DBSPACETEMP 环境变量或配置参数设置后,临时表会自动创建在由 DBSPACETEMP 环境变量或配置参数指定的数据空间上;如果数据库采用日志模式,那么创建的临时表缺省情况下是记日志的,不会被创建在由 DBSPACETEMP 环境变量或配置参数指定的数据空间上,那么由SELECT ... INTO TEMP语句创建的临时表将被创建在根数据空间(root dbspace)上,由CREATE TEMP TABLE语句创建的临时表将被创建在数据库所在的数据空间上。如果希望临时表创建在由 DBSPACETEMP 环境变量或配置参数指定的数据空间上,我们需要使用 SELECT INTO TEMP with no log 语句或 CREATE TEMP TABLE with no log 语句来创建临时表。

    下面的表格详细说明了临时表的数据存储位置的各种情况:

    Case A: select * from tab1 into temp tmp1 或者

    create temp table tmp1(c1 int);

    Case B: select * from tab1 into temp tmp1 with no log; 或者

            create temp table tmp1(c1 int) with no log;

    数据库demodb创建在dbs1

    DBSPACETEMP 设置为tmpdbs

    DBSPACETEMP不设定

    DB with LOG

    DB No-Log

    DB with LOG

    DB No-Log

    A

    B

    A

    B

    A

    B

    A

    B

    rootdbs

    dbs1

    tmpdbs

    tmpdbs

    tmpdbs

    dbs1

    dbs1

    dbs1

    dbs1

           表格浅绿色部分情况是日志数据库中为了考虑性能所期望的一种临时表存储方式:日志数据库设定DBSPACETEMP参数为tmpdbs,我们在创建临时表时加上with no log选项,临时表将会将数据存储在临时表空间tmpdbs上。

           另外,正如smart large objects需要SBSPACEDBS一样,也需要为大对象临时表设置相应的临时存储数据空间SBSPACETEMP。为了性能考虑,我们一般都要配置多个SBSPACETEMP数据空间。

    临时表优化建议

    从上面的描述,我们可以得知不管是由用户创建的临时表,还是由系统自动创建的临时表都需要进行存储,用户创建的临时表某些情况下还需要记录日志。出于性能考虑,我们从如下两个方面提高临时表的性能。

    1.        取消日志

    在日志数据库中,通过with no log选项,取消临时表的DML操作的日志,这样能大大提高数据处理效率。另外,尤其是在有 HDR 辅助服务器、RS 辅助服务器或 SD 辅助服务器的数据复制环境中,因为其防止 Informix 通过网络传输临时表。

    2.        利用临时表空间

    通过如下原则利用临时表空间提高临时表的性能:

    n          创建独立的临时表空间,防止与root dbspace及默认表空间的I/O争用情况;

    n          创建多个临时表空间,并正确配置DBSPACETEMP参数;

    n          为临时表空间分配足够大的存储空间,防止出现临时表空间不足的情况;

    n          大数据临时表以round-robin模式分布在多个临时表空间上。并且设置PDQ priority>0,可以提高临时表数据并发处理效率;

    n          根据临时表存储表空间使用原则,使用with no log选项;

    n          临时表空间不能使用direct I/O,所以你需要分配足够的AIO VPs

    IDS11新特性

    在采用日志模式的数据库中,对无with no log选项的临时表的所有DML操作都要记日志。当不加 with no log 选项时,临时表不会创建在由DBSPACETEMP环境变量或配置参数指定的临时数据空间上,往往将数据写到rootdbs或者默认数据库空间上,大大影响了系统性能。而且用户在创建临时表时,有时会忘记 with no log 选项。为了解决上述问题,IDS 11 版本开始提供了关闭对临时表记日志的TEMPTAB_NOLOG参数,建临时表时,即使没加 with no log 选项,临时表也会创建在由 DBSPACETEMP 环境变量或配置参数指定的临时数据空间上。

    我们可以采用下述两种方法来关闭对临时表记日志:

    方法一

    修改onconfig配置参数

    TEMPTAB_NOLOG 1

     

     

    方法二onmode命令动态修改

    onmode -Wf TEMPTAB_NOLOG=1 或者

    onmode -Wm TEMPTAB_NOLOG=1

    -Wm 选项改变参数值后立即生效; -Wf 选项改变参数值后立即生效,同时将新的参数值写到 onconfig 配置文件中

    约束

           以下为Informix临时表、临时表空间的几点约束:

    n         在数据库服务器重启时,临时表空间将被清空;

    n         临时表不能进行备份、恢复;

    n         临时表空间不能使用direct I/O,所以你需要分配足够的AIO VPs

    n         临时表的列上不能创建外关联约束;

     

    展开全文
  • 临时表和表变量,转载自博客园

    千次阅读 2012-06-13 16:20:00
    临时表 Vs 表变量 开始 说临时表和表变量,这是一个古老的话题,我们在网上也找到很多的资料阐述两者的特征,优点与缺点。这里我们在SQL Server 2005\SQL Server 2008版本上通过举例子,说明临时表和表...

    原文地址:http://www.cnblogs.com/wghao/archive/2011/11/02/2227219.html

     

    临时表 Vs 表变量

    开始


    说临时表和表变量,这是一个古老的话题,我们在网上也找到很多的资料阐述两者的特征,优点与缺点。这里我们在SQL Server 2005\SQL Server 2008版本上通过举例子,说明临时表和表变量两者的一些特征,让我们对临时表和表变量有进一步的认识。在本章中,我们将从下面几个方面去进行描述,对其中的一些特征举例子说明:

    • 约束(Constraint)
    • 索引(Index)
    • I/0开销
    • 作用域(scope)
    • 存儲位置
    • 其他

     

    例子描述


    约束(Constraint)

               在临时表和表变量,都可以创建Constraint。针对表变量,只有定义时能加Constraint。

    e.g.在Microsoft SQL Server Management Studio(MSSMS)查询中,创建临时表并建Constraint场景,<脚本S1.>

    Use tempdb
    go
    if object_id('Tempdb..#1') Is Not Null 
       Drop Table #1                
    Go
    Create Table #1
    (
     ID int,
     Nr nvarchar(50) not null,
     OperationTime datetime default (getdate()),
     Constraint PK_#1_ID Primary Key (ID)
    )
    
    Alter Table #1 Add Constraint CK_#1_Nr Check(Nr Between '10001' And '19999')
    Go
    

    < 脚本S1.>中,可以看出在临时表#1的创建时,创建Constraint如“Constraint PK_#1_ID Primary Key(ID)”,也可以在创建临时表#1后创建Constraint,如“Alter Table #1 Add Constraint CK_#1_Nr Check(Nr Between '10001' And'19999')”,下面我们来看表变量的场景,在定义表变量时不能指定Constraint名,定义表变量后不能对表变量创建Constraint。

    e.g. 在定义表变量时不能指定Constraint名<代码S2.>

    Use tempdb
    Go
    Declare @1 Table
    (
     ID int,
     Nr nvarchar(50) not null,
     OperationTime datetime default (getdate()),
     Constraint [PK_@1_ID] Primary Key (ID)
    )
    
     

    image

     

    在定义表变量后不能对表变量创建Constraint,<代码S3.>

    use tempdb
    go
    Declare @1 Table
    (
     ID int primary key clustered,
     Nr nvarchar(50),
     OperationTime datetime default (getdate())
    )
    
    Alter Table @1 Add Constraint [CK_@1_Nr] Check(Nr Between '10001' And '19999')
    

    image

     

    在<代码S2.>和<代码S3.>中可以发现,在解析T-SQL语法过程就发生错误,也就是SQL Server不支持定义表变量时对Constraint命名,也不支持定义表变量后,对其建Constraint。

     

    这里慎重提示下,在<代码S1.>给临时表建Constraint的时候,特别是在并发场景中,不要指定具体的Constraint名称,不然会发生对象已存在的错误提示。

    e.g. 在MSSMS中我们先执行之前<代码S1.>的创建临时表#1,不关闭当前会话的情况下,另建一个查询,执行与<代码S1.>相同的代码,如图

    image

     

    左边的查询窗口,是执行原先的<代码S1.>,右边的查询窗口,是后执行相同的<代码S1.>。在这里,我们注意红色圈圈部分,发现在创建临时表#1的过程,明确给了一个主键名称“PK_#1_ID”,当右边再创建相同临时表#1的时候就发生了对象重复错误问题。我们也可以通过SQL Server提供的系统视图sys.objects查询约束“PK_#1_ID”的信息,

    use tempdb
    
    go
    
    Select * from sys.objects Where name='PK_#1_ID'
    

    image

    在系统视图sys.objects,发现“PK_#1_ID”名称后面不加如何的随机数值表述不同会话有不同的对象。根据SQL Server对sys.objects的描述规则,sys.objects中的Name列数据是唯一的。当另一个会话创建相同的对象时就会发生对象重复的错误。

     

    在Constraint中,Foreign Key是不能应用与表变量,对于临时表,创建Foreign Key是没有意义的。也就是说临时表不受Foreign Key约束。下面我们通过例子来说明临时表的情况,

    e.g.< 脚本S4.>

    use tempdb
    go
    if object_id('Tempdb..#1') Is Not Null
        Drop Table #1                
    Go
    if object_id('Tempdb..#2') Is Not Null
        Drop Table #2                
    Go
    Create Table #1
    (
    
        ID int,
        Nr nvarchar(50) not null,
        OperationTime datetime default(getdate()),
        Constraint PK_#1_ID Primary Key(ID)
    )
    Alter Table #1 Add Constraint CK_#1_Nr Check(Nr Between '10001' And '19999')
    Create table #2
    (
        ID int Primary Key,
        ForeignID int Not null ,foreign Key(ForeignID) References #1(ID)
    )
    Go

     

    image

     

    可以看出对于临时表不强制Foreign Key约束,我们也可以通过SQL Server系统视图sys.foreign_keys查询

    use tempdb
    go
    Select * from sys.tables Where name like '#[1-2]%'
    Select * From sys.foreign_keys
    

    image

    右边的查询,只看到在sys.tables表哦中存在刚才创建的临时表#1和#2,在sys.foreign_keys看不到有关Foreign Key约束信息。这也验证了左边SQL Server提示的,在临时表中无法强制使用Foreign Key约束。

     

    索引(Index)

    从索引方面看临时表和表变量,与从Constraint上分析有些类似,在临时表中,它与真实表一样可以创建索引。在表变量定义过程中,也可以创建一些类似唯一和聚集索引。

    e.g.< 脚本S5.>

    use tempdb
    
    go
    
    declare @1 Table(      
    
                    ID int  primary key clustered,
    
                    Nr nvarchar(50) unique Nonclustered
    
    )
    
    Insert into @1 (id,Nr) values(1,'10001')
    
    Insert into @1 (id,Nr) values(2,'10002')
    
    Insert into @1 (id,Nr) values(8,'10003')
    
    Insert into @1 (id,Nr) values(3,'10004')
    
    Insert into @1 (id,Nr) values(7,'10005')
    
    Select top 2 *
    
                    From sys.indexes As a
    
                                    Inner Join sys.tables As b On b.object_id=a.object_id
    
                    Order by b.create_date Desc
    
    Select Nr From @1 Where Nr='10005'
    
    go
    

     

    image

    image

    上面截的是两张图,第一张图描述在表变量使聚集Primary Key,创建非聚集的Unique约束,第二张图描述查询语句”Select Nr From @1 Where Nr='10005'” 应用到在表变量创建的唯一索引“UQ_#……”

    是于临时表索引的例子,我们拿一个例子说明,与前边说的Constraint例子有点相似,这里我们对临时表创建索引,并给索引一个具体名称,测试是否会重复。

    e.g.在MSSMS新增两个查询,编写下面的SQL语句:

    < 脚本S6.>

    Use tempdb
    Go
    if object_id('#1') is not null    
        Drop Table #1 
        
    Create Table #1
    (
     ID int primary key,
     Nr nvarchar(50) not null,
     OperationTime datetime default (getdate()),
    )
    
    create nonclustered index IX_#1_Nr on #1(Nr Asc)
    go
    Select b.name As TableName,
           a.* 
        from sys.indexes As a
            Inner join sys.tables As b On b.object_id=a.object_id
        Where b.name like '#1[_]%'
        Order by b.create_date Asc

     

    image

     

    从返回的结果,我们看到在系统视图表Sys.Indexes中,创建有两个相同的索引”IX_#1_Nr”,但注意下object_id数据不同。在SQL Server中是允许不同的表索引名称可以相同的。在并发的环境下,按原理是可以对临时表创建的索引给明确名称的。除非并发的情况会发生重复的表名或重复的Constraint,或其它系统资源不足的问题,才会导致出错。

     

    I/0开销

    临时表与表变量,在I/O开销的描述,我们直接通过一个特殊的例子去描述它们,在MSSMS上新增两个查询,分别输入临时表和表变量的测试代码:

    e.g.< 脚本S7.>临时表:

    Use tempdb
    Go
    if object_id('#1') is not null    
        Drop Table #1 
        
    Create Table #1
    (
     ID int primary key,
     Nr nvarchar(50) not null,
     OperationTime datetime default (getdate())
    )
    
    Insert into #1(ID,Nr,OperationTime)
    Select top 50000 row_number()over (order by a.object_id),left(a.name+b.name,50) ,a.create_date
        from master.sys.all_objects As a ,sys.all_columns As b
        Where type='S'
    
    
    
    Select Nr,count(Nr) As Sum_ 
        From #1 
        Where Nr like 'sysrscolss%'    
        Group by Nr
    

    < 脚本S8.>表变量:

    Use tempdb
    Go
    Declare @1 Table
    (
     ID int primary key,
     Nr nvarchar(50) not null,
     OperationTime datetime default (getdate())
    )
    
    Insert into @1(ID,Nr,OperationTime)
    Select top 50000 row_number()over (order by a.object_id),left(a.name+b.name,50) ,a.create_date
        from master.sys.all_objects As a ,sys.all_columns As b
        Where type='S'
        
    
    Select Nr,count(Nr) As Sum_ 
        From @1 
        Where Nr like 'sysrscolss%'    
        Group by Nr
    

     

    image

     

    < 脚本S7.>和< 脚本S8.>,主要是看最后的查询语句I/O的开销,两者有何不同。通过上面的运行结果图形描述,可以看出查询开始,不管是临时表还是表变量,都使用到了聚集索引扫描(Clustered Index Scan),两者虽然返回的数据一致,但I/O的开销不同。临时表的I/O开销是0.324606,而表变量只有0.003125 相差非常大。在临时表的执行计划图形中,我们发现一行“缺少索引(影响 71.9586):CREATE ……)”提示信息。我们对临时表#1,在字段“Nr”上创建一个非聚集索引,再看执行执行结果:

    create nonclustered index IX_#1_Nr On #1(Nr)

    image

    我们在临时表#1上创建完索引“IX_#1_Nr”,运行看上面的图形显示,就感觉非常的有意思了。在临时表#1查询时用了索引搜索(Index Seek),而且I/O开销减少到了0.0053742。虽然开始查询的时候I/O开销还是比表变量开始查询的时候大一些,但执行步骤中比变变量少了一个“排序(Sort)”开销,后最后的看回Select结果,估计子树的成本比使用表变量的大大减少。

    这里的例子只是描述一个特殊的情况,在真实的环境中,要根据实际的数据量来判断是否使用临时表或表变量。倘若在存储过程中,当数据量非常少如只有不到50行记录,数据占的页面也不会超过1个页面,那么使用表变量是一个很好的解决方案。

     

    作用域(scope)

    表变量像局部变量(local variable)一样,有着很窄的作用域,只能应用于定义的函数、存储过程或批处理内。如,一个会话里面有几个批处理,那么表变量只能作用在它定义所在的批处理范围内。其他的批处理无法再调用它。

    e.g.在MSSMS新增一个查询,编写< 脚本S9.>

    use tempdb
    Go
    Set Nocount on
    declare @1 Table(      
                    ID int  primary key clustered,
                    Nr nvarchar(50) unique Nonclustered
    )
    Insert into @1 (id,Nr) values(1,'10001')
    Insert into @1 (id,Nr) values(2,'10002')
    Insert into @1 (id,Nr) values(8,'10003')
    Insert into @1 (id,Nr) values(3,'10004')
    Insert into @1 (id,Nr) values(7,'10005')
    
    Select * From @1
    
    Go --批处理结束点
    
    Select * From @1

     

    image

    < 脚本S9.>所在的查询相当于一个会话,”Go”描述的一个批处理的结束点。在”Go”之前定义的表变量,在”Go”之后调用是发生“必须声明变量@1”的错误提示。

    临时表与表变量不同,临时表的作用域是当前会话都有效,一直到会话结束或者临时表被Drop的时候。也就是说可以跨当前会话的几个批处理范围。

    e.g.< 脚本S10.>

    Use tempdb
    go
    if object_id('Tempdb..#1') Is Not Null 
       Drop Table #1                
    Go
    Create Table #1
    (
     ID int,
     Nr nvarchar(50) not null,
     OperationTime datetime default (getdate()),
     Constraint PK_#1_ID Primary Key (ID)
    )
    Select * from #1
    
    go --批处理结束点
    
    Select * from #1
    

    image

    < 脚本S10.>中可以看出在”GO”前后都可以查询到临时表#1。

    在描述临时表与表变量的作用域时,有个地方要注意的是,当 sp_executesql 或 Execute 语句执行字符串时,字符串将作为它的自包含批处理执行. 如果表变量在sp_executesql 或 Execute 语句之前定义,在sp_executesql 或 Execute 语句的字符串中无法调用外部定义的表变量。

    e.g.< 脚本S11.>

    use tempdb
    go
    Set nocount on
    declare @1 Table(      
                    ID int  primary key clustered,
                    Nr nvarchar(50) unique Nonclustered
    )
    Insert into @1 (id,Nr) values(1,'10001')
    Insert into @1 (id,Nr) values(2,'10002')
    Insert into @1 (id,Nr) values(8,'10003')
    Insert into @1 (id,Nr) values(3,'10004')
    Insert into @1 (id,Nr) values(7,'10005')
    
    Select * From @1
    
    Execute(N'Select * From @1')
    
    go
    

    image

    < 脚本S11.>中,当执行到”Execute(N'Select * From @1')”时候,同样发生与< 脚本S9.>一样的错误提示“必须声明变量@1”.

    临时表是可以在sp_executesql 或 Execute 语句执行字符串中被调用。这里不再举例子,如果你有所模糊可以参考< 脚本S11.>把表变量转成临时表测试下就能加深理解与记忆。

     

     

    存儲位置

    说到临时表和表变量的存储位置,我们可以看到有很多版本的说法,特别是表变量。有的说表变量数据存储在内存中,有的说存储在数据库tempdb中,有的说有部分存储在内存,部分存储在数据库tempdb中。根据我查到的官方资料,说的是在SQL Server 2000下:

    A table variable is not a memory-only structure. Because a table variable might hold more data than can fit in memory, it has to have a place on disk to store data. Table variables are created in the tempdb database similar to temporary tables. If memory is available, both table variables and temporary tables are created and processed while in memory (data cache).

    在SQL Server 2005\SQL2008的版本,表变量存储与临时表有相似,都会在数据库tempdb创建,使用到tempdb存储空间。

    e.g.< 脚本S12.>临时表

    use tempdb
    go
    Set nocount on
    
    Exec sp_spaceused /*插入数据之前*/
    
    if object_id('#1') Is not null 
        Drop Table #1 
        
    create table #1(ID int ,Nr nvarchar(50))
    Insert into #1  (ID,Nr)
        Select top(1) row_number() Over(order By a.object_id),left(a.name+b.name,50)
            From sys.all_objects As a,
                sys.all_columns As b    
                                    
    Select top(1) name,object_id,type,create_date from sys.tables Order by create_date Desc            
    
    Exec sp_spaceused /*插入数据之后*/
    Go
    
    

    image

    在< 脚本S12.>执行后,我们可以看到在数据库tempdb中的表sys.tables创建有表#1。我们接着看空间的使用情况,插入数据之前,数据库未使用空间(unallocated space)为510.39MB,向临时表#1插入1条数据后,数据库未使用空间为501.38MB,未使用空间变小了。再来看整个数据库的数据(data)使用的空间变化,从552KB变成560KB,使用了一页的数据空间(8kb)。这说明一点,临时表,即使你只插入一条数据都会使用到数据库tempdb的空间。也许会有人问,要是我只建临时表#1,不插入数据,会如何。我们可以结果:

    image

    这里你会发现前后的空间大小不变,不过,不要认为没有使用到数据库tempdb数据空间,当你多用户创建临时表结构的时候,你就会发现其实都会应用到数据库tempdb的空间。我这里创建了10个#1后的效果如:

    image

     

    相同的原理,我们使用类似的方法测试表变量的情况,发现结论是与临时表的一致的,会使用到数据库tempdb的空间.

    e.g.< 脚本S13.>表变量

    use tempdb
    go
    Set nocount on
    Exec sp_spaceused /*插入数据之前*/
    
    Declare @1 table(ID int ,Nr nvarchar(50))
    Insert into @1  (ID,Nr)
        Select top(1) row_number() Over(order By a.object_id),left(a.name+b.name,50)
            From sys.all_objects As a,
                sys.all_columns As b            
                
    Select top(1) name,object_id,type,create_date from sys.objects Where type='U' Order by create_date Desc            
    
    Exec sp_spaceused /*插入数据之后*/
    
    Go
    Exec sp_spaceused /*Go之后*/
    

    image

    < 脚本S13.>中,我多写了一个”GO”之后检查空间大小的存储过程sp_spaceused。这样为了了更能体现表变量使用空间变化情况。从插入数据前和插入数据后的结果图来看,表变量不仅在数据库tempdb创建了表结构#267ABA7A类似的这样表,表变量也应用到了数据库tempdb的空间。不过这里注意一点就是在”Go”之后,我们发现表变量@1,会马上释放所使用的数据空间。为了更能体现使用空间情况。我们可以向表变量@1插入大量数据看空间变化情况(测试插入1000万的数据行)。

    e.g.< 脚本S14.>

    use tempdb
    go
    Set nocount on
    Exec sp_spaceused /*插入数据之前*/
    
    Declare @1 table(ID int ,Nr nvarchar(50))
    Insert into @1  (ID,Nr)
        Select top(10000000) row_number() Over(order By a.object_id),left(a.name+b.name,50)
            From sys.all_objects As a,
                sys.all_columns As b            
                
    Select top(1) name,object_id,type,create_date from sys.objects Where type='U' Order by create_date Desc            
    
    Exec sp_spaceused /*插入数据之后*/
    
    Go
    Exec sp_spaceused /*Go之后*/
    

    image

    这里我们可清晰的看到数据库tempdb的大小(database_size)变化情况,从插入数据前的552.75MB变成插入数据之后的892.75MB。非常有意思的是我们在”Go之后”发现数据库大小保存在892.75MB,但数据使用空间(data)从560KB—>851464KB—>536KB ,说明SQL Server自动释放为使用的数据空间,但不会马上自动释放数据库分配的磁盘空间。我们在实际的环境中,发现临时数据库tempdb使用的磁盘空间越来越大,这是其中的原因之一。

     

     

    其他

    临时表与表变量,还有其他的特征,如临时表受事务回滚,而表变量不受事务回滚影响。对应事务方面,更为正确的说法是表变量的事务只在表变量更新期间存在。因此减少了表变量对锁定和记录资源的需求。

    e.g.< 脚本S15.>

     

    use tempdb
    go
    Set nocount on
    
    if object_id('#1') Is not null 
        Drop Table #1     
    create table #1(ID int ,Nr nvarchar(50))
    Declare @1 table(ID int ,Nr nvarchar(50))
    
    begin tran /*开始事务*/
    
    Insert into #1  (ID,Nr)
        Select top(1) row_number() Over(order By a.object_id),left(a.name+b.name,50)
            From sys.all_objects As a,
                sys.all_columns As b    
    
    
    Insert into @1  (ID,Nr)
        Select top(1) row_number() Over(order By a.object_id),left(a.name+b.name,50)
            From sys.all_objects As a,
                sys.all_columns As b    
                
    rollback tran /*回滚事务*/
    
    Select * from #1
    Select * from @1
    
    Go
    
    

    image

    这里发现”Rollback Tran”之后,临时表#1没有数据插入,而表变量@1还有一条数据存在。说明表变量不受”Rollback Tran”所影响。它的行为有类似于局部变量一样。

    另外SQL Server对表变量不保留任何的统计信息,因为如此,我们在数据量大的时候使用表变量,发现比临时表要慢许多。前面在I/O开销那里我们取有一个特殊的例子,这里不再举例。

     

    小结

    无论如何,临时表和表变量有各自的特征,有自己优点和缺点。在不同的场景选择它们灵活应用。本文章是我对临时表和表变量的一些认识理解,可能有些地方说的不够好或者遗漏,你可以留言或Email与我联系,我会继续改进或纠正,我也不希望有些错误的见解会误导别人。正如Phil Factor说的一句" I'd hate to think of anyone being misled by my advice!".

     

    附参考:

    http://support.microsoft.com/kb/305977/en-us

    http://stackoverflow.com/questions/27894/whats-the-difference-between-a-temp-table-and-table-variable-in-sql-server

    http://msdn.microsoft.com/en-us/library/aa175774(SQL.80).aspx

    http://msdn.microsoft.com/en-us/library/cc966545.aspx

    http://www.simple-talk.com/sql/t-sql-programming/temporary-tables-in-sql-server/

    http://support.microsoft.com/kb/942661/en-us

    展开全文
  • 临时表和表变量的区别。这是第三次遇到了。今次必须解决该问题。经过前两次蜻蜓点水式的查询相关资料,这次记录了下来,尽快详细深入处理一下这个盲点!

    首先,本文摘抄了别人的文章以及书籍。

    悲催了。在ef4中使用临时表无法获得返回类型的变量。因此,全部弄回了表变量。写了一坨重复代码。靠!这个问题一定要解决掉!!!!!!!!


    1、临时表
    临时表包括:以#开头的局部临时表,以##开头的全局临时表。
    a、存储
    不管是局部临时表,还是全局临时表,都会放存放在tempdb数据库中。
    b、作用域
    局部临时表:对当前连接有效,只在创建它的存储过度、批处理、动态语句中有效,类似于C语言中局部变量的作用域。
    全局临时表:在所有连接对它都结束引用时,会被删除,对创建者来说,断开连接就是结束引用;对非创建者,不再引用就是结束引用。
    但最好在用完后,就通过drop table 语句删除,及时释放资源。
    c、特性
    与普通的表一样,能定义约束,能创建索引,最关键的是有数据分布的统计信息,这样有利于优化器做出正确的执行计划,但同时它的开销和普通的表一样,一般适合数据量较大的情况。
    有一个非常方便的select ... into 的用法,这也是一个特点。


    2、表变量
    a、存储
    表变量存放在tempdb数据库中。
    b、作用域
    和普通的变量一样,在定义表变量的存储过程、批处理、动态语句、函数结束时,会自动清除。
    c、特性
    可以有主键,但不能直接创建索引,也没有任何数据的统计信息。表变量适合数据量相对较小的情况。
    必须要注意的是,表变量不受事务的约束,


    摘抄2

    脚本之家的博文

    脚本之家的这篇文章描述的比较详细

    摘抄3

    博客园博文

    博客园这篇也挺好。留给自己作为参考。最快也得等到晚上了。。。


    自己写的一个存储过程,朋友指出的问题

    1、

     你前面没有创建临时表的语句 :说明在前面要声明临时表
    2、没创建的话用不着清表,要么清,要么删,不用清完后在删
    3、SELECT * into 少用些



    展开全文
  • Hibernate 关系描述之OneToMany

    千次阅读 2013-08-06 08:30:21
    Hibernate 关系描述之OneToMany  上篇写了一对一,那么在这篇我们讲一对多,那么在中的一对多,是使用外键关联,通过一张的一个键另一个的外键来建立一多关系;  而在类中表示为一个类中有一个集合...

    Hibernate 表关系描述之OneToMany

     上篇写了一对一,那么在这篇我们讲一对多,那么在表中的一对多,是使用外键关联,通过一张表的一个键另一个表的外键来建立一多关系;
     而在类中表示为一个类中有一个集合属性包含对方类的很多对象,而在另一个类中,只包含前术类的一个对象,从而实现一对多关系的建立!
     而在Hibernate中采用的是Set类型集合,而使用<one-to-many>主<many-to-one>来实现,好了,我们来看一下:
    首先看看表结构!

    customer表:

    create  table customers
    (
        ID  bigint  not  null     primary  key auto_increment,
        userName  varchar( 20)
    );
    Order表:
    create  table orders
    (
        ID  bigint  not  null  primary  key auto_increment,
        customers_ID  bigint,     -- 应该为customers(ID)外键
        orderDescription  varchar( 50) -- 订单描述
    );

    有了上面简单的客户表与订单表,来建立一个Project!~并且添加Hibernate~并由上面二张表生成Beans,主键都是native类型~自动递增!
    我们将 自动生成的Customer.java    Bean添加一个SET属性,代码如下:


    package fengyan.Hibernate;

    import java.util.HashSet;
    import java.util.Set;

    /**
     *Authod:    fengyan
     *    date:    2006-12-30 01:02    
     
    */


    public class Customers  implements java.io.Serializable {


        // Fields    

         private Long id;
         private String userName;

         //必须定义一个Set集合类型的属性以及它的get和set方法,
         
    //它持有一个Customers对象所发出的所有订单的引用
         private Set orders = new HashSet();

        // Constructors

        public Set getOrders() {
            return orders;
        }



        public void setOrders(Set orders) {
            this.orders = orders;
        }



        /** default constructor */
        public Customers() {
        }


        
        /** full constructor */
        public Customers(String userName) {
            this.userName = userName;
        }


       
        // Property accessors

        public Long getId() {
            return this.id;
        }

        
        public void setId(Long id) {
            this.id = id;
        }


        public String getUserName() {
            return this.userName;
        }

        
        public void setUserName(String userName) {
            this.userName = userName;
        }


    }


    为Order.java   Bean 去掉cid(CustomerID)并添加一个Customer属性,代码如下:


    package fengyan.Hibernate;
    /**
     *Authod:    fengyan
     *    date:    2006-12-30 01:02    
     
    */


    public class Orders  implements java.io.Serializable {


        // Fields    

         private Long id;
      //   private Long customersId;
         private String orderDescription;

         //添加一个Customers属性,用来引用一个订单对象所属的客户对象
         private Customers customer;
        // Constructors

        public Customers getCustomer() {
            return customer;
        }



        public void setCustomer(Customers customer) {
            this.customer = customer;
        }



        /** default constructor */
        public Orders() {
        }


        public Orders(String description)
        {
            this.orderDescription = description;
        }

       
        // Property accessors

        public Long getId() {
            return this.id;
        }

        
        public void setId(Long id) {
            this.id = id;
        }


       
        public String getOrderDescription() {
            return this.orderDescription;
        }

        
        public void setOrderDescription(String orderDescription) {
            this.orderDescription = orderDescription;
        }

    }

     


    修改Customer.hbm.xml映射文件:

    <? xml version="1.0" encoding="GBK" ?>
    <! DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
    >

    < hibernate-mapping >
         < class  name ="fengyan.Hibernate.Customers"  table ="customers"  catalog ="study" >
             < id  name ="id"  type ="java.lang.Long" >
                 < column  name ="ID"   />
                 < generator  class ="native"   />
             </ id >
             < property  name ="userName"  type ="java.lang.String" >
                 < column  name ="userName"  length ="20"   />
             </ property >
            
             <!--  name集合属性orders    
                 table对应的表名    
                 cascade 级联关系,当保存或更新时会级联保存与这个Customers对象相关联的所有Orders对象
                 inverse=true是将 控权抛出(给Orders) 
    -->
             < set  name ="orders"  table ="orders"  cascade ="save-update"  inverse ="true" >
                 < key  column ="customers_ID" ></ key > <!--  表字段  -->        
                 < one-to-many  class ="fengyan.Hibernate.Orders" /> <!--  关联的类  -->
             </ set >
         </ class >
    </ hibernate-mapping >


    修改Order.hbm.xml,内容如下:

    <? xml version="1.0" encoding="utf-8" ?>
    <! DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
    >

    < hibernate-mapping >
         < class  name ="fengyan.Hibernate.Orders"  table ="orders"  catalog ="study" >
             < id  name ="id"  type ="java.lang.Long" >
                 < column  name ="ID"   />
                 < generator  class ="native"   />
             </ id >
           
             < property  name ="orderDescription"  type ="java.lang.String" >
                 < column  name ="orderDescription"  length ="50"   />
             </ property >
            
             <!--  name属性名
                 class对应的类
                 column对应的表字段 
    -->
             < many-to-one  name ="customer"  class ="fengyan.Hibernate.Customers"  column ="customers_ID" ></ many-to-one >
         </ class >
    </ hibernate-mapping >

    然后我们建立一个CustomersDAO操作类

    package fengyan.Hibernate;

    import org.hibernate.Session;
    import org.hibernate.Transaction;

    public  class CustomersDAO  {
        
        public void save(Customers customer)
        {
            Session session = HibernateSessionFactory.getSession();//会话
            try
            {
                Transaction tx = session.beginTransaction();//事物
                session.save(customer);//保存
                tx.commit();//提交事物
            }

            catch(Exception e)
            {
                System.out.println("DAO has Errors:"+e);
            }

            finally
            {
                session.close();//关闭会话
            }

        }


    }

    再来建立一个Servlet     MyServlet.java代码如下:

    package fengyan.Hibernate;

    import java.io.IOException;
    import java.io.PrintWriter;

    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;

    public  class MyServlet  extends HttpServlet  {

        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {

            //声明一个用户
            Customers customer = new Customers("fengyan");
            
            //声明二订单
            Orders order1 = new Orders("描述1");
            Orders order2 = new Orders("描述2");
            
            //订单关联用户
            order1.setCustomer(customer);
            order2.setCustomer(customer);
            
            //用户关联订单
            customer.getOrders().add(order1);
            customer.getOrders().add(order2);
            
            //save
            CustomersDAO cd = new CustomersDAO();
            cd.save(customer);//我们仅仅保存了Customers!
            
        }

    }

    最后一个JSP测试页面:

    <% @ page language="java" import="java.util.*" pageEncoding="ISO-8859-1" %>
    < html >
       < head >      
         < title >My JSP 'index.jsp' starting page </ title >  
       </ head >  
       < body >
        < br >
        < href ="servlet/MyServlet" >add </ a >
       </ body >
    </ html >

    运行效果如下:

    我们可以看到,在doGet()方法中,我产仅仅save(customer),并没有save(order)但却执行了三条SQL,由显示的SQL语句我们可以知道,将用户fengyan添加到Customers表中的同时也将 order1及order2添加到Orders表中!
    为什么Hibernate会自动帮我们将订单也添加到表中呢,就是我们在Customers.hbm.xml映射配置中,set节点的cascade=save-update,就是当我们保存或更新Customers的时候也会自动保存相应的Orders对象!

    当我们现在将 doGet()方法内  订单关联用户的代码注释掉,看一下效果:

    从显示的SQL语句看,我们似乎看不出什么区别,但这时如果打开MYSQL,会发现:

    我们发现现在Hiberante帮自动插入的Customers_ID字段为空,为什么会这样的呢,我们不是在下面用

    // 用户关联订单
      customer.getOrders().add(order1);
      customer.getOrders().add(order2);


    不是已经由用户关联了订单吗?这是因为我们在Customers.hbm.xml的set节点中加了属性inverse=true,这句话的意思是将主控制权交出去,具体是什么意思呢?就是在一对多关系中将 主动权交出,具体也就是交给了Orders,也就是用户与订单之间从属关系主要是由Orders对象来确定,也即订单自己来决定它属于哪个对象,所以在这里,我们将    订单关联用户的代码注释掉后,虽然后面 用户关联了订单,但因为用户已经将主动权交出,所以Hibernate在帮我们save订单的时候并不知道订单是属于哪个用户,也自然就在Customers_ID字段填空值了!
    那么如果此时我们将Customers.hbm.xml中的 inverse=true去掉是不是就行了呢?带着这样的猜想,我来尝试一下,结果如下图:


    我们首先查寻数据库发现Hibernate已经正确的将Orders对象持久化到表中了,

    同时我们看控制台监视的SQL语句,这时我们发现有五条语句,前三条分别是添加一个用户和二条订单,四五条是修改订单的,具体修改什么,我们发现是修改了customers_ID字段,原来这种情况,Hibernate是先将 订单持久化到表中,因为我们注释了订单关联用户的代码,所以Hibernate还是先插入空值,然后再根据我们的 用户关联订单 再来更新Orders表将 Customers_ID字段修改为正确的值!
    这个时候我们发现,虽然这样可以,但还是会有一些问题,因为当数据量很大的时候,这样的操作是很占资源的,会影响性能,同时如果我们的数据库customers_ID字段定义为not null,非空,那么可想而知这种方式是不可行的!
    那么可不可以将inverse=true加上,Customers将主动权交出后,我们仅仅用订单关联用户,而用户关联订单的注释掉呢?我们式式!
    运行结果我们发现仅仅是将 用户添加到表中去了,而订单却丢失,这为什么,不是用户将主动权交出,而我们也用订单关联了用户,为何没有加入订单呢,首先要知道,关联是仅仅减缓到订单属于哪个用户,也就是关联订单的customers_ID字段!但用户类里,属性 Set orders = new HashSet();初始是为空的,这样虽然订单关联了用户,但用户对象内的orders属性还是为空,订单还没产生呢,这样Hibernate自然在保存用户的时候,判断集合为空,自然不会去添加订单!这个有点像什么呢,就好比腾讯的QQ宠物里面的所谓“超值大礼包”,每一种礼包我们可以认为是一个订单,而这样的“礼包”一产生也的属于对象,当然就是属于所有拥有QQ宠物的QQ号了!这可以认为上 订单关联了对象,但至于在操作对象的时候,订单有没有,这个其实还是由QQ号码决定的,看它要不要,它如果要了,就有订单,不要呢,当然就没订单了,虽然腾讯希望订单是属于他的!我个人觉得这个比如很恰当!

    所以得出总结是:无论我们的Customer类是否将主动权交出去,我们都要将用户关系到订单!那可能会想:既然这样交不交主动权有什么区别呢?有!而且很大!就像我们一开始运行的效果。

    如果我们将 用户主动权交出,通过监视的SQL我们可以看到只执行了三条SQL语句,分别说是插入用户和二条订单!没有更新!
    而如果我们没有将Customers主动权交出的话,运行效果如下:
     
    有五条语句,性能不一样,同时可以解决comstomers_ID字段不为空的问题!所以一般我们还是会选择交出主动权!

    另外补充一下cascade的属性值:

    <!--
    none:在保存,更新或删除当前对象时,忽略其他关联的对象。它是cascade属性的默认值
    save-update:当通过Session的save()以及saveOrUpdate()方法来保存或更新当前对象时,级联保存所有关联的新建的临时对象,并且级联更新所有关联的游离对象。
    delete:当通过Session的delete()方法删除当前对象时,级联删除所有关联的对象。
    all: 包含save-update以及delete的行为。此外,对当前对象执行evict()或lock()操作时,也会对所有关联的持久化对象执行evict()或lock()操作。
    delete-orphan:删除所有和当前对象解除关联关系的对象。
    all-delete-orphan:包含all和delete-orphan的行为
    -->


    转载出处:http://www.cnblogs.com/eflylab/archive/2006/12/30/606607.html
     

    展开全文
  • MySQL: SELECT同时UPDATE同一张

    千次阅读 2019-03-18 10:17:54
    当然,有比创建无休止的临时表更好的办法。 本文解释如何UPDATE一张表,同时在查询子句中使用SELECT. 问题描述 假设我要UPDATE的表跟查询子句是同一张表,这样做有许多种原因,例如用统计数据更新表的字段(此时...
  • 上传图片的时候,如果要修改图片的后缀,那需要先获取该图片的临时存储文件,然后用GD库函数打开,获取图片资源,然后重新定义后缀存储,那么这个临时文件是什么呢,图片资源和咱们平时所用的文件资源又有什么区别呢...
  • 资料备查 :) 转自xiaocong117的blogT000: 消费者T000C: 用于安装FI-SL用户化设置的T000CM: 依客户而定的 FI-AR-CR 设置T000F: 跨集团 FI 设置T000G: 跨客户总分类帐记帐T000GL: 灵活总帐: 定制检查和激活T000K: 组...
  • Android面试过程描述

    万次阅读 2013-11-09 00:27:19
    3、关于android平时很少用到但实则很重要的问题描述 技术分析 1自我感觉面试中比较好的方面: 1、熟悉掌握之前所写项目 2、能够及时对没有接触过的问题做出通过自己的推理做出正确的解答。 2自我感觉面试中比较不好...
  • MySQL优化器成本记录

    万次阅读 2021-08-18 20:26:02
    不过我们之前对成本的描述是非常模 糊的,其实在MySQL中一条查询语句的执行成本是由下边这两个方面组成的: IO成本 我们的经常使用的MyISAM、InnoDB存储引擎都是将数据和索引都存储到 磁盘上的,当我们想查询中...
  • Oracle 查询技巧与优化(二) 多查询

    万次阅读 多人点赞 2016-08-05 08:59:59
    关于Oracle多查询的一些技巧和优化~
  • ) 临时表L LEFT JOIN 表A ON 表A.IDENT = 临时表L.IDENT ) 临时表k LEFT JOIN 表B ON 表B.CODE = 临时表k.code 以上三个版本在通过表C对应获取表B数据的时候,都能正确获取,但是当一起对应输出的时候,数据就不对...
  • 1.数据库设计14规则 1. 原始单据与实体之间的关系   可以是一对一、一对多、多对多的关系。...这里的实体可以理解为基本。明确这种对应关系后,对我们设计录入界面大有好处。   〖例1〗:一份员工履
  • Mysql错误编码和解释

    万次阅读 2017-09-19 20:58:54
    Mysql错误编码和解释1.错误消息的组成一共由三部分组成 1.mysql数字错误代码,这个数字的mysql的特定值,不可以移植到其它数据库系统。 2.一个五位长度的sqlstate值,这些值取自ANSI SQL和ODBC,并且更加标准化。...
  • oracle空间传输

    千次阅读 2013-03-01 17:11:27
    空间传输一、简介可传输空间(还有个集)最大的优势是其速度比export/import或unload/load要快的多。因为可传输空间主要是复制数据文件到目标路径,然后再使用export/import或Data Pump export/import等应用仅...
  • 借用这段逻辑地址空间,建立映射到想访问的那段物理内存(即填充内核PTE页面),临时用一会,用完后归还。这样别人也可以借用这段地址空间访问其他物理内存,实现了使用有限的地址空间,访问所有所有物理内存 ...
  • MySQL SELECT同时UPDATE同一张

    万次阅读 多人点赞 2013-02-19 01:05:50
    当然,有比创建无休止的临时表更好的办法。本文解释如何UPDATE一张表,同时在查询子句中使用SELECT. 问题描述 假设我要UPDATE的表跟查询子句是同一张表,这样做有许多种原因,例如用统计数据更新表的字段(此时...
  • 以前在美国学Java数据结构的时候,因为当时是插班生,临时选的数据结构,其实当时还没学Java,听到hash table一脸懵逼,回公寓在goole和百度上也没有找到比较完整的解释,最近在看python数据结构的时候又重新研究了...
  • Oracle的种类及定义

    千次阅读 2015-10-24 15:09:43
    1的类型 1)堆组织(heap organized tables). 当增加数据时,将使用在段中找到的第一个适合数据大小的空闲空间.当数据从中删除时,留下的空间允许随后的insert和update重用. 2)索引组织. 这里存储在索引...
  • MySQL支持很多种不同的数据类型,并且选择正确的数据类型对于获得高性能至关重要。不管选择何种类型,下面的简单原则都会有助于做出更好的选择: (1).更小通常更好 一般来说,要试着使用正确地存储和表示数据...
  • 0.11 GDT是如何建立的

    千次阅读 2008-06-24 17:07:00
    在保护模式下,段寄存器所存储的将是段描述的某个索引值,索引值指定的段描述符项中含有需要寻址的内存段的基地址、段的最大长度值和段的访问级别等信息。计算线性地址的示意图如下:   因此,在进入保护...
  • MySQL高级特性一:分区

    万次阅读 2019-01-22 17:31:26
    对用户来说,分区时一个独立的罗技,但是底层由多个无力字组成。实现分区的代码实际上是对一组底层的句柄对象的封装。对分区的请求,都会通过句柄对象转化成对存储引擎的接口调用。所以分区对于SQL层来说...
  • 将一个链表分为奇偶两个链表

    千次阅读 2019-06-30 13:52:26
    1. 问题描述: 设计一个算法,将一个头结点为A的单链表(其数据域为整数)分解成两个单链表A和B,使得A链表只含有原来链表data域为奇数的节点,而B链表只含有原链表中data域为偶数的节点,而且保持原来的顺序 2. ...
  • 正确编写概要设计说明书

    万次阅读 2009-11-03 15:38:00
    正确编写概要设计说明书 在需求明确、准备开始编码之前,要做概要设计,而详细设计可能大部分公司没有做,有做的也大部分是和编码同步进行,或者在编码之后。因此,对大部分的公司来说,概要设计文档是唯一的设计...
  • DB2代码 错误信息描述

    千次阅读 2012-08-30 10:17:14
    ALTER不能用于改变列的长度,因为该列参与了RI、一个用户退出程序、全局的临时表或打开DATACAPTURE CHANGES表的列 -150 42807 触发活动的INSERT,UPDATE或DELETE语句中指定了无效的视图更新或一个...
  • Oracle数据库,实例,空间,用户,之间的关系简析
  • 链表添加函数中为什么要用指向链表指针的指针

    万次阅读 多人点赞 2016-02-03 22:41:09
     网上其他人的博客中对函数AddToTail的参数的描述跟书中如出一辙:第一个参数pHead是一个指向指针的指针,当向一个空链表插入一个节点时,新插入的节点是链表的头指针,此时会改动头指针,因此必须把pHead参数设置...
  • ORA-00942: --table or view does not exist 或者视图不存在 ORA-01400: --cannot insert NULL into () 不能将空值插入 ORA-00936: --缺少表达式 ORA-00933: --SQL 命令未正确结束
  • SAP 汇总

    千次阅读 2016-10-22 14:07:37
    SAP 整理: VBKPF-预制凭证抬头: VBKPF-预制凭证抬头 VBKPF-预制凭证抬头 VBSEG-预制凭证行项目: VBSEG-预制凭证行项目 VBSEG-预制凭证行项目 VBSEGA-预制凭证行项目_资产: VBSEGA-预制凭证...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 88,951
精华内容 35,580
关键字:

关于临时表的描述正确的是