存档

‘Sybase ASE’ 分类的存档,文章数:183

配置篇

2.1 如何配置字符集的转换类型

禁用字符集转换的配置方法
在isql 环境中执行:
1> sp_configure “disable character set conversion”,1
2> go
“disable character set conversion” 参数默认配置值为0 ,即启用字符集转换。

如何配置字符集的转换类型
把”enable unicode conversions” 参数设置为1 或者2 。当配置为1 时,此设置使用直接转换或Unicode 转换;当配置为2 时,此设置使用Unicode 转换;默 认配置值为0 ,使用直接转换。

在isql 环境中执行:
1> sp_configure ”enable unicode conversions”,1
2> go

2.2 如何配置服务器端缺省字符集
直接转换法
直 接转换法是指直接使用Sybase 提供的实用程序,如UNIX 平台上使用sqlloc 命令或者编辑sqlloc.rs 脚本文件;Windows 平台使用 “ 服务器配置” 图形化管理工具直接配置服务器端字符集。

使用直接转换法的条件是:
―― 服务器中没有用户数据
―― 对服务器中用户数据的损坏是可以接受的
―― 绝对确定服务器中的数据只使用ASCII-7 字符集

间接转换法
间接转换法相对于直接转换法而言,需要通过一下三步来完成配置工作:
1. 先将服务器端的数据使用bcp 命令导出
2. 再选择直接转换法之中的一种方式配置服务器端字符集
3. 再使用带有-J 参数的bcp 命令把数据导回服务器端

配置服务器端字符集的方法 sqlloc— 适用于UNIX 平台的命令
在$SYBASE_OCS/bin 目录下执行:sqlloc ,将出现一个图形化界面,在这个界面中您可以直接选择语言集,字符集,排序顺序,便很容易地就 完成了配置工作。

编辑sqlloc.rs 脚本文件
将$SYBASE-ASE/init /sample_resource_files/sqlloc.rs 拷贝到$SYBASE_OCS/bin 目录下,按以下黑体字提示编辑该文件:
sybinit.release_directory: /home/sybase――― 输入Sybase 产品的安装路径
sqlsrv.server_name: SYB125――― 输入数据库服务器的名称
sqlsrv.sa_login: sa
sqlsrv.sa_password: ――― 输入sa 的口令,若为空,则什么也不填
sqlsrv.default_language: us_english――― 输入想要配置的语言集
sqlsrv.language_install_list: USE_DEFAULT
sqlsrv.language_remove_list: USE_DEFAULT
sqlsrv.default_characterset: cp850――― 输入想要配置的字符集
sqlsrv.characterset_install_list: USE_DEFAULT
sqlsrv.characterset_remove_list: USE_DEFAULT
sqlsrv.sort_order: binary――― 输入想要配置的排序顺序
# An example sqlloc resource file…
# sybinit.release_directory: USE_DEFAULT
# sqlsrv.server_name: PUT_YOUR_SERVER_NAME_HERE
# sqlsrv.sa_login: sa
# sqlsrv.sa_password:
# sqlsrv.default_language: french
# sqlsrv.language_install_list: spanish,german
# sqlsrv.language_remove_list: USE_DEFAULT
# sqlsrv.default_characterset: cp437
# sqlsrv.characterset_install_list: mac,cp850
# sqlsrv.characterset_remove_list: USE_DEFAULT
# sqlsrv.sort_order: dictionary

保存已经修改好的sqlloc.rs 脚本文件,执行以下命令:
sqllocres -r sqlloc.rs

注意屏幕上出现的提示信息,如无异常,则完成配置工作。

服务器配置” 图形化管理工具―― 适用于Windows 平台
“ 服务器配置” 管理工具提供了一个易于操作的图形化管理平台,根据工具中提示的信息,很容易就完成了字符集的配置工作,这里就不多讲了,请参看相关文档说 明。

2.3 如何配置客户端缺省字符集
配置客户端缺省字符集实际上就是对“$SYBASE\locales” 目录下locales.dat 文件的修改。

Windows 平台用写字板方式打开该文件,在UNIX 平台可以直接使用“vi” 命令打开该文件,我们会看到,该文将中所有字符集的配置都是以服务器端操 作系统平台名称分组的:
.
.
[aix]
locale = C, us_english, iso_1
locale = En_US, us_english, iso_1
locale = en_US, us_english, iso_1
locale = default, us_english, iso_1
locale = En_US.IBM-850, us_english, cp850
locale = en_JP, us_english, eucjis
locale = Fr_FR, french, cp850.
.
[axposf]
locale = C, us_english, iso_1
; Use Posix Locales, straight from the Posix Guidelines
locale = en_US.88591, us_english, iso_1
locale = fr_FR, french, iso_1
locale = zh_CN, chinese, eucgb
locale = zh_TW, tchinese, euccns
locale = ko_KR, korean, eucksc
locale = us_english.utf8, us_english, utf8
locale = default, us_english, iso_1
.
.
其中,操作系统名称放在每一组最开始的“[]” 中,而且请注意上面黑体字,每一组中都会存在一行“locale = default,…” 。我们要修改客户端的默认字符集,就是对这一行进行修改。

例如,某系统服务器端是SUN 平台,服务器端语言集为english ,字符集为cp850 。我们要修改客户端字符集与服务器端一致,怎么做? 首先找到[SUN] 操作系统分组,然后修改“locale = default,…” 为“locale = default,us_English,cp850” 。
修改前:
[sun]
; from JLE, KLE, CLE, OS/4.1.1, man setlocale()
; and Sun Software Internationalization Guide (p/n 800-5972-08)
; use setenv LC_CTYPE, LC_MESSAGES, LANG
locale = C, us_english, iso_1
locale = fr, french, iso_1
locale = de, german, iso_1
locale = tr, us_english, iso88599
locale = zh, chinese, eucgb
locale = zh_CN, chinese, eucgb
locale = zh_TW, tchinese, euccns
locale = ko, korean, eucksc
locale = us_english.utf8, us_english, utf8
locale = default, us_english, iso_1

修改后:
[sun]
; from JLE, KLE, CLE, OS/4.1.1, man setlocale()
; and Sun Software Internationalization Guide (p/n 800-5972-08)
; use setenv LC_CTYPE, LC_MESSAGES, LANG
locale = C, us_english, iso_1
locale = fr, french, iso_1
locale = de, german, iso_1
locale = tr, us_english, iso88599
locale = zh, chinese, eucgb
locale = zh_CN, chinese, eucgb
locale = zh_TW, tchinese, euccns
locale = ko, korean, eucksc
locale = us_english.utf8, us_english, utf8
locale = default, us_english, cp850

保存该文件,就完成对客户端字符集的修改了。

这里,还要说明一种特殊情况:
为了满足服务器端某些应用的特殊需求,在服务器端设置了一个环境变量:LANG, 此时客户端字符集该如何设置呢?

例如,某系统服务器端是Windows 平台,使用语言集english ,字符集iso_1 ,并设置环境变量LANG=C 。我们要修改客户端字符集与服务器 端一致,怎么做?

首先找到[NT] 操作系统分组,然后在该组中加入一行
“locale = C,us_English,iso_1”
修改前:
[NT]
locale = enu, us_english, iso_1
locale = fra, french, iso_1
locale = deu, german, iso_1
locale = japanese, japanese, sjis
locale = chs, chinese, eucgb
locale = cht, tchinese, big5
; locale = kor, korean, eucksc
locale = us_english.utf8, us_english, utf8
locale = default, us_english, iso_1

修改后:
[NT]
locale = enu, us_english, iso_1
locale = fra, french, iso_1
locale = deu, german, iso_1
locale = japanese, japanese, sjis
locale = chs, chinese, eucgb
locale = cht, tchinese, big5
; locale = kor, korean, eucksc
locale = us_english.utf8, us_english, utf8
locale = default, us_english, iso_1
locale = C,us_English,iso_1
因此在修改客户端字符集之前,请先查看服务器端是否设置了环境变量“LANG“ ,再决定如何修改。

2.4 如何选择ASE 字符集使之支持简体中文字符
目前在ASE 12.5 中支持中文字符的字符集有四种:CP936 ,EUCGB ,UTF-8 和GB18030 。

其中EUCGB 字符集是基于GB2312-80 编码规范的,它的EUC (Extended Unix Code) 编码范围是第一字节0xA1~0xFE( 实际只用到0xF7) ,第二字节0xA1~0xFE 。

CP936 字符集是基于GBK 编码规范(实际上的国家标准是GB13000-90 ),是对GB2312 进行的扩展,第一字节为0×81~0xFE ,第二字 节分两部分,一是0×40~0×7E ,二是0×80~0xFE 。其中和GB2312 相 同的区域,字完全相同。

GB18030 字符集(国家标准号是GB18030-2000 )是2000 年3 月17 日发布的新的中文编码标准。它是GB2312 的扩充,采用单/ 双/ 四 字节编码体系结构,收录了27000 多个汉字以及臧文、蒙文、维吾尔文等主要的少数民族文字。Sybase 从ASE 12.5.0.3 之后开始支持GB18030 字符集。

UTF-8 字符集是现有ASCII 系统向Unicode 转换的一个过渡方案。它使用1-3 字节表示一个字符。简体中文的每个字符在utf8 中的长度基本上 都是3 个字节。它的最主要的优点是可以同时支持超过650 种语言的字符。缺点是针对中文字符来说,需要增加50% 的空间用来存储。还有一个问题是执行 sp_helptext 显示存储过程体的时候,有可能出现半个汉字。

一般来说,由于EUCGB 不支持国标一、二级字库以外的汉字,所以我们推荐用户在服务器端和客户端都使用CP936 字符集,或者在ASE 12.5.0.3 之后还可以使用GB18030 字符集,它可以支持一些比较生僻的汉字。它的不足是只有一种排序方式,即区分大小写的Binary 方式。所 以,如果需要使用支持中文字符集且不区分大小写的数据库时,就只能使用UTF-8 作为服务器端字符集,而客户端使用CP936 或GB18030 字符集。

另外,还有一种选择是,服务器端和客户端都使用iso_1 字符集,虽然iso_1 字符集并不直接支持中文字符,但我们将服务器端和客户端都设置成 iso_1 字符集后,系统也不会在客户端和服务器端进行字符转换,它只不过将一个汉字的两个字节当做两个单独字符来处理,一般情况下没有问题。但当执行 like 匹配查询的时候,它有可能返回不正确的结果,原因是服务器端是根据单字节去匹配查询条件的,很可能会有前一个汉字的第二字节与后一个汉字的第一字 节的内码组合符合查询条件,被服务器端作为查询结果返回来。

2.5 如何查看服务器端、客户端字符集
查看服务器端字符集:
在isql 环境中执行:
1> sp_helpsort
2> go
查看客户端字符集:
在isql 环境中执行:
1> select @@client_csname
2> go

3. 错误处理篇
3.1 为什么会出现字符集转换失败
1. 当字符存在于客户端字符集中但在服务器字符集中不存在时,Adaptive Server 的字符集转换将报告转换错误,反之亦然。
用户会碰到下面的错误消息:
Msg 2402,Severity 16 (EX_USER):
Error converting client characters into server’s character set. Some character(s) could not be converted.
转换错误会阻止插入与更新语句的执行。如果发生此情况,请检查数据中有问题的字符并替换它们。

2. 当客户端发送数据时Adaptive Server 遇到转换错误,它用ASCII 码的问号(?)代替可疑字符所占字节,但查询批处理继续进行直到完成为止。
语句完成后,Adaptive Server 将发送一下消息:
Msg 2403,Severity 16 (EX_USER):
WARNING! Some character(s) could not be converted into client’s character set. Unconverted bytes were changed to question marks (`?’) 。

3. 当在客户端查询服务器端存储的数据时,当碰到中文汉字,在客户端显示乱码的现象,且没有任何提示信息。这是我们在应用中经常会碰到的现象,产生的原因是: 客户端与服务器端字符集不符。怎么解释呢?假设我们先期设置服务器端字符集为iso_1 ,客户端字符集也为iso_1, 然后我们从客户端向服务器端录入了 所有的数据;之后当我们需要查询时,使用的客户端,它的字符集为cp850 ,那么势必在该客户端上显示的字符集为乱码。

当出现这种情况时,最好配置客户端字符集为先期客户端使用的字符集或者配置客户端字符集与服务器端字符集一致,使得客户端字符集与服务器端字符集匹配。这 里我们不建议用户修改服务器端字符集,因为服务器中此时已经存在大量的数据,在使用直接转换方式时,由于源字符集与目的字符集中可能存在无法转换的字符而 导致Adaptive Server 无法启动;如果使用间接的转换方式,会增加工作量。

4. 附:如何安装cp936 字符集
以在Windows 平台安装cp936 字符集为例,说明如何安装使用服务器中没有被默认安装的字符集。( 在ASE 12.5.0.3 版本中安装GB18030 字符集的方法类似)
( 这里SYBASE 的安装路径为c:\sybase)
1.c:\>cd \sybase\charsets\cp936
2.c:\sybase\charsets\cp936> charset -Usa -Psa_pass -Sserver_name binary.srt cp936
3. 在SQL 环境中 1>select name,id from syscharsets
2>go
找到name 为cp936 对应的id( 假设为171)
4.1>sp_configure "default character set id",171
2>go

5. 重启server 两次
(注: 第一次启动后,server 会自动宕掉,需要第二次重启后才能使用)

EBF

官方软件发行版本。EBF号唯一性地标志了在某个OS平台上的发行版本。

ESD

官方软件发行版本,它解决了当前发行版本中的一些Bug。ESD(ESD #)通常是跨平台的,并且不包含新的特性或功能。ESD是征对某一主版本(major version)的累积软件包,它必须在GA发行版本上安装。

GA

GA(General Availability)是一个SYBASE软件版本全新的、初始听发行版本。除Bug修复之外,它通常包含一些新特性。

IR

IR(Interim Release-中间版本)包含了在此之前的所有ESD发行版本的Bug修复,以及其它Bug修复。IR发行版本必须基于与之对应的GA发行版本的基础上 安装。比如,要安装12.5.0.3,就必须先安装12.5GA(ESD)。

MR

MR(Maintenance Release-维护版本)是GA发行版本的完整替换包。由于它是完整的发行包,因此可以直接安装。通常此种类型的发行版本包含一些新特性以及Bug修复。

先来介绍一下裸设备的知识

1.什么是裸设备(RAW DEVICE)
裸设备是指未创建文件系统的磁盘分区(raw partition)或逻辑卷(raw logical volume),应用程序直接通过一
个字符设备驱动程序对它进行访问。如何对设备上的数据读写决定于使用它的应用程序。由于对裸设备的操作不通过UNIX的缓冲区,数据在ORACLE的数据 缓冲区(BUFFER CACHE)和磁盘之间直接传递,所以使用裸设备在一定程度上能够提高I/O性能,适合I/O量大的系统。另外OPS/RAC (Oracle Parallel Server/Real Application Cluster)环境下,多个节点同时访问同一个数据库,所以CONTROL FILE、DATA FILE、REDO LOG都必须建在RAW DEVICE上。

2.裸设备的可用空间
不同的UNIX对裸设备的管理不完全相同,特别要注意的是某些UNIX在每个裸设备的头部要保留一定的空间,应用程序在使用裸设备时不可以覆盖这一部分, 否则会对裸设备造成损坏。所以一个裸设备的实际可用空间是分配给裸设备的空间再减去这部分操作系统保留空间。下面是常用UNIX的OS Reserved Size列表:
UNIX     OS Reserved Size
------------ ----------------
SUN Solaris       0
HP-UX          0
IBM AIX         4k
Tru64 UNIX       64k
Linux          0
3.如何读裸设备上的数据?

UNIX上读写裸设备不能使用cp, cpio, tar等命令,必须用dd,下面是几个dd常用参数的简单说明,更详细的信息请参考UNIX使用手册或用命令man dd。
dd [ operand=value ... ]
if=file 指定输入文件,缺省值是标准输入
of=file 指定输出文件,缺省值是标准输出
bs=n 设置输入和输出的块大小为n字节,也可以用“k”作单位
skip=n 在拷贝之前跳过n个输入块,缺省值是0
seek=n 在拷贝之前从输出文件首部跳过n块,缺省值是0
count=n 指定拷贝的块数,缺省拷贝到输入文件结束

4.用十六进制读取unix的文件系统上的文件

介绍一下od命令的用法,linux od(octal dump) 命令详解
功能说明:输出文件内容。
语  法:od [-abcdfhilovx][-A <字码基数>][-j <字符数目>][-N <字符数目>][-s <字符串字符数>][-t <输出格式>][-w <每列字符数>][--help][--version][文件...]

补充说明:od指令会读取所给予的文件的内容,并将 其内容以八进制字码呈现出来。

参  数:
-a  此参数的效果和同时指定"-ta"参数相同。
-A<字码基 数>  选择要以何种基数计算字码。
-b  此参数的效果和同时指定"-toC"参数相同。
-c  此参数的效果和同时指定"-tC"参数相同。
-d  此参数的效果和同时指定"-tu2"参数相同。
-f  此参数的效果和同时指定"-tfF"参数相同。
-h  此参数的效果和同时指定"-tx2"参数相同。
-i  此参数的效果和同时指定"-td2"参数相同。
-j<字符数目>或--skip-bytes=<字符数目>  略过设置的字符数目。
-l  此参数的效果和同时指定"-td4"参数相同。
-N<字符数目>或--read- bytes=<字符数目>  到设置的字符数目为止。
-o  此参数的效果和同时指定"-to2"参数相同。
-s<字符串字符数>或--strings=<字符串字符数>  只显示符合指定的字符数目的字符串。
-t<输 出格式>或--format=<输出格式>  设置输出格式。
-v或--output-duplicates  输出时不省略重复的数据。
-w<每列字符数>或--width=<每列字符数>  设置每列的最大字符数。
-x  此参数的效果和同时指定"-h"参数相同。
--help  在线帮助。
--version  显示版本信息。

5.实例

用od命令读solaris上的文件,以十六进制的形式显示结果

bash-3.00$ uname -a
SunOS sunv890 5.10 Generic_137111-08 sun4u sparc SUNW,Sun-Fire-V890
bash-3.00$ od -t x4 master.dat | head -10
0000000 00000800 00000002 00000000 00000014
0000020 00000002 00000000 00000005 00000000
0000040 00000019 00008706 0000000c 00002710
0000060 000001f4 00000000 00001000 00000000
0000100 00000064 00000006 00000000 00000000
0000120 00000000 00002000 0000000a 00000001
0000140 4e554c4c 00000000 00000000 00000000
0000160 00002000 00000200 00001000 00000050
0000200 00000000 00000000 00000000 00000000
*
bash-3.00$

上面是我在solaris sparc平台上执行od命令用16进制读取文件的结果。

最左边用红色标记的是偏移量(八进制形式)。如:0000000表示偏移0,0000020表示偏移16(因为0000020(o)=16(d)),0000040表示偏移32。。。

od -t x4 master.dat 这条命令的意思是:用od读取master.dat文件的内容,用16进制的形式显示结果,并且每四个字节为一个显示单位,之间用空格分隔。一般都是每行显示16个字节的数据。

head -10 这条命令的意思是只显示前10行的数据。

在IBM-AIX上读取文件内容

-bash-3.2$ prtconf
System Model: IBM,7044-170
Machine Serial Number: 10D908C
Processor Type: PowerPC_POWER3
Processor Implementation Mode: POWER 630
Processor Version: PV_630
Number Of Processors: 1
Processor Clock Speed: 333 MHz
CPU Type: 64-bit
Kernel Type: 64-bit
以上为系统配置

-bash-3.2$ od -t x4 master.dat |head -10
0000000 00000000 00000000 00000000 00000000
*
0010000 00000800 00000002 00000000 00000014
0010020 00000002 00000000 00000005 00000000
0010040 00000019 00009481 0000000c 00002710
0010060 000001f4 00000000 00001000 00000000
0010100 00000064 00000006 00000000 00000000
0010120 00000000 00002000 0000000a 00000001
0010140 4e554c4c 00000000 00000000 00000000
0010160 00002000 00000200 00001000 00000050
-bash-3.2$

说明:中间的红色星号是od命令显示出来的,非人工添加。最左边红色一列表示偏移量(8进制形式)。第一行的偏移为0,并且结果好像都是0(ascii中的0)。然后第二行的偏移量就变成了4096(0010000(o)=4096(d) )。右边的数据是master.dat文件中的内容。以16进制的形式显示出来,每行16字节,每四个字节为一个单位,之间用空格分隔。

可以看出在ibm-aix powerpc平台上文件系统的数据是从4096偏移处开始存储的。前4096字节的内容为文件的控制信息。

用UltraEdit读取windows平台上的文件master.dat。

00000000 | 00 00 00 00 03 00 00 00 A6 00 00 00 63 00 00 00 | ...........c... | ....¦.c.
00000010 | 01 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 | ................ | ......̀.
00000020 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ | ........
00000030 | 01 00 00 00 00 00 00 00 01 00 00 00 FF 00 00 00 | ............... | ......ÿ.
00000040 | 01 00 00 00 00 00 00 00 01 00 00 00 0F 00 03 00 | ................ | ........
00000050 | 02 00 00 00 00 00 00 00 02 00 00 00 FF 00 00 00 | ............... | ......ÿ.
说明:最左边一列表示偏移量(16进制数据)。中间的部分数据是文件master.dat的内容。

windows上的文件自偏移0开始存储,没有类似ibm-aix上的类似的前4096字节的控制内容。

在linux平台上读取文件的16进制数据的结果,我这边只有一个32bit的虚拟机。就不演示了。

大家可以对比上面的显示结果。发现文件系统或者裸设备的文件可用空间和上面介绍的常用UNIX的OS Reserved Size列表是一致的。

————————————————————————————————————
——— 本文为andkylee个人原创,请在尊重作者劳动成果的前提下进行转载;
——— 转载务必注明原始出处 : http://www.dbainfo.net
——— 关键字:unix hex file system raw device 文件系统 裸设备 od
————————————————————————————————————

在sybase中复制数据时,经常能够解决到bcp(bulk copy)。

bcp分两种,快bcp和慢bcp。这两种分法是针对bcp in。对于bcp out个人感觉没有快、慢之分,反正就是从sybase的extent上大块大块的拷数据。

今天在bcp 数据in 到一个sybase server的时候,报下面的错误:

C:\Documents and Settings\Administrator>bcp test.dbo.tablename in d:\12
34 -c -Usa -Saix
Password:
Starting copy...
Server Message: SYB_AIX53 - Msg 4806, Level 16, State 1:
You cannot run the non-logged version of bulk copy in this database. Please chec
k with the DBO.
Server Message: SYB_AIX53 - Msg 3621, Level 10, State 0:
Command has been aborted.
CTLIB Message:  - L1/O3/S0/N14/0/0:
blk_init(): blk layer: CT library error: Failed when CT_Lib routine ct_results()
 called.
blk_init failed.
bcp copy in failed

上error message & troubleshooting guide上查看一下错误编号为:4806的信息。

解释如下:

This error occurs when the select/into bulkcopy option is set to “false” and you
use “fast” bulk copy into a table that has no indexes.
Note In newly created databases, the select into/bulkcopy option is set (by
default) to the same as that in model.

解决的办法有两种:

第一:

启用目的库的"select/into bulkcopy"选项,使用fast bcp模式。这样会不计日志(实际上是记录很少很少的日志记录),也就是说:这不能保证数据库日志的一致性,最好对目的数据库做一个完全备份(dump database),之后才能备份日志。

补充一点:针对有些不计日志的操作导致备份日志不能执行的问题,唯一的办法就是对库做全备。但是,尤其在select into/bulk选项被打开的数据库上,你如何知道这个数据库里曾经执行了不计日志的操作呢?15.0以前的版本是没有好办法的,只能在发出dump tran命令的时候提示不能备份日志需先全备。这是很等的不方便啊~
终于在15.0版本中,千呼万唤始出来。sybase给我们送来了福音。增加了函数:tran_dumptable_status(),用来返回一个是否允许 dump transaction 的真/ 假指示。
如果 tran_dumpable_status 返回 0,则可以对数据库执行 dump transaction
命令。如果返回任何其它值,则无法执行该命令。非零值有:
 1 — 指定名称的数据库不存在。
 2 — 日志没有放置在单独的设备上。
 4 — 日志首页位于仅限数据的磁盘片段区域内。
 8 — 为数据库设置了 trunc log on chkpt 选项。
 16 — 在数据库上发生了未记录的写入操作。
 32 — 仅截断 dump tran 已中断发送到转储设备的任意连续的转储
系列。
 64 — 最近创建或升级了数据库。在执行 dump database 之前,不会
转储事务日志。
现在终于可以在备份脚本加入tran_dumptable_status(),如果返回0,表示可以正常执行备份日志任务。如果返回非0尤其16或者32的时候,先执行数据库全备再执行dump tran操作。

第二:给将要拷贝数据的表上添加索引,让bcp使用慢模式。这样目的数据库会正常的记录日志。就像一条一条的insert语句那样。因此,不会出现完备后 才能备份日志的情况了。但是要注意防止大量的写入操作导致目的数据库日志被写满。可以在bcp in的时候适当时间执行dump transaction with truncate_only,也可以数据分批bcp导入(需要加入-b选项)。

————————————————————————————————————
——— 本文为andkylee个人原创,请在尊重作者劳动成果的前提下进行转载;
——— 转载务必注明原始出处 : http://www.dbainfo.net
——— 关键字:sybase BCP fast 日志 索引  快bcp  慢bcp 完整备份 日志备份
————————————————————————————————————

本帖子转自:echoaix  嘟嘟之家  http://blog.chinaunix.net/u/10212/showart.php?id=88834

向echoaix这位sybase 高手表示感谢。

转下面内容的原因是作个记录方便以后来查看如何在unix下修改文件内容。在windows下以十六进制形式修改文件内的数据很简单,可以用 UltraEdit这个强大的工具。我编出来了工具能够实现从sybase数据设备文件中提取数据和翻译解析sybase日志设备文件内容,这个过程中 UE提供了莫大的帮助。我编写的工具跟UE没有关系。但是,有时候对sybase设备文件做一个小小的修改的时候,我喜欢用UE。

但是,在unix环境下的sybase设备文件该如何修改呢?总不能每次都ftp下载下来,用windows下的Ultraedit改好了后再上传到服务器吧?

这样做太麻烦。

幸运的是,早有高手提供了解决的方法!厉害!

下面的代码我没有完全看明白,主要是没unix写过shell的原因。

大概意思是:向sh脚本传递3个参数,用指定数据替换指定文件中的相应偏移的相同字节的数据。

用od定位出被修改的偏移位置。然后用echo向dd传入数据,dd会处理这个文件。

至于如何将4个字节的数据转化到数组里的那段代码,我没有看懂!

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

环境 :
iBM aix 4.3和sybase11.9 只有这环境
master设备/dev/rlvsybmaster1
前面还是一样看page内容:
dbcc traceon(3604)
go
dbcc tablealloc(sysdatabases) 或  select first from sysindexes where id = object_id("sysdatabases" and indid=1\\找到数据页(pageno)
go
dbcc page(master,pageno,1,0)  \\从硬盘上拿这页内容详细内容
go
master的如下:
Offset 266 -
3256210a:  02000001 00010000 80000001 000008a1  ................
3256211a:  00000000 00000000 00009179 00fe9caa  ...........y....
3256212a:  0005adda 00120034 6d617374 65728000  .......4master..
3256213a:  03302e28                             .0.(.
用od命令定位(od命令真好)
#od -H /dev/lvsybmaster1 |grep '02000001 00010000 80000001 000008a1'
报找不到,郁闷,仔细看看dbcc page用法1(print page header, data rows and row offset table), 2 (print page header and hex dump of data page) 。改用dbcc page(master,pageno,2,0)
结果如下:不只这些,择了master的
32562110:  00008000 00010000 08a10000 00000000  ................
32562120:  00000000 917900fe 9caa0005 adda0012  .....y..........
32562130:  00346d61 73746572 80000330 2e280201  .4master...0.(..
32562140:  00030001 00000000 00010000 01e00000  ................
32562150:  00000000 00000000 917900fd acd60013  .........y......
32562160:  9866001e 00336d6f 64656c80 00032f2d  .f...3model.../-
原来是顺序不同,怪不得grep找不到,再来:
#od -H /dev/lvsybmaster1 |grep '00008000 00010000 08a10000 00000000' 结果
2024420  00008000 00010000 08a10000 00000000  找到,注意这的偏移量是8进制的
找到如何改呢?知道应该用dd,叨咕半天,不行,上网求助 ,在liveunix看到“炸鸡”高人的帖子,给了一个sh如下
cat chvgid.sh
#!/usr/bin/ksh
vgid=$1
disk=$2

set -A a `echo $vgid|\
awk '{
for (f=1; f <= length($0); f=f+2) {
print "ibase=16\nobase=8\n"toupper(substr($0,f,2))
}
}'|bc 2>/dev/null`
/usr/bin/echo "\0"${a[0]}"\0"${a[1]}"\0"${a[2]}"\0"${a[3]}"\c"|dd bs=1 seek=3600 of=/dev/$disk
原来他是要直接改VGID的信息,看来能改的东西真不少。
到现在这个sh我还是看不很明白,但是用没问题,自己改了改如下
#cat chfile.sh
#!/usr/bin/ksh
dstatus=$1
filename=$2
offset=$3

set -A a `echo $dstatus|\
awk '{
for (f=1; f <= length($0); f=f+2) {
print "ibase=16\nobase=8\n"toupper(substr($0,f,2))
}
}'|bc 2>/dev/null`

/usr/bin/echo "\0"${a[0]}"\0"${a[1]}"\0"${a[2]}"\0"${a[3]}"\c"|dd bs=1 seek=$offset of=$filename conv=notrunc
加了$3偏移量,还有注意加conv=notrunc,要不你在修改点后的数据可能都没了。这的偏移量可是10进制的
od -Ad -H /dev/lvsybmaster1 |grep '00008000 00010000 08a10000 00000000' 找10进制偏移
0534800  00008000 00010000 08a10000 00000000
停sybase
改master设备
#chfile.sh 00000000 /dev/lvsybmaster1 534800
4+0 records in.
4+0 records out.
就是要把00008000 改为00000000
重启sybase ok

迄今已分析出来了sybase中索引(indid>1)的物理存储结构。

索引结构是B-Tree类型的。最顶部叫做根(root),最底层称为叶子(leaf)。一个表可能建有好几个非聚簇索引,这时indid依次为2,3,。。。递增。

对于一个索引,比如indid=2的那个。索引树状结构是分层次的,在sybase数据存储中用level表示,根部级别最高,叶子的级别最低。叶 子(leaf)的级别level为0,往上索引层level为1,再往上位2,。。。最后到达顶部root级别为(N-1,N为所有的层次数)。

不管APL还是DOL表,索引的每层(level)上的页面都是前后链接起来的,这一点有点像APL表中的数据页面上的前、后页链(data page link)。

以下简要演示分析索引结构的过程。

1.

设定成在终端显示dbcc结果信息。

1
2
dbcc traceon(3604)
go

2.

查看syspartitions表的信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
1> select *from sysobjects
2> where name='PartitionTestTable'
3> go
name
id          uid         type userstat sysstat indexdel schemacnt
sysstat2    crdate                     expdate
deltrig     instrig     updtrig     seltrig     ckfirst     cache
audflags    objspare    versionts
loginame
identburnmax                              spacestate
erlchgts
-----------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
----------------------------------------------------------------------------
----------- ----------- ---- -------- ------- -------- ---------
----------- -------------------------- --------------------------
----------- ----------- ----------- ----------- ----------- ------
----------- ----------- --------------------------
------------------------------
----------------------------------------- ----------
------------------
PartitionTestTable
1223672376           1 U           0      99        2         0
73728        Feb 24 2010  4:43PM        Feb 24 2010  4:43PM
0           0           0           0           0      0
0           0 NULL
NULL
NULL       NULL
NULL
(1 row affected)
1> select * from syspartitions
2> where id =  1223672376
3> go
name
indid  id          partitionid segment status      datoampage
indoampage  firstpage   rootpage    data_partitionid
crdate
cdataptnname
-----------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
----------------------------------------------------------------------------
------ ----------- ----------- ------- ----------- -----------
----------- ----------- ----------- ----------------
--------------------------
---------------------------------------------------------------------------------
------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------
zhang
0  1223672376  1239672433       1           0       61288
0       61289       61997                0
Feb 24 2010  4:43PM
NULL
liu
0  1223672376  1255672490       1           0       61296
0       61297       62124                0
Feb 24 2010  4:43PM
NULL
wang
0  1223672376  1271672547       1           0       61304
0       61305       62260                0
Feb 24 2010  4:43PM
NULL
li
0  1223672376  1287672604       1           0       61312
0       61313       62385                0
Feb 24 2010  4:43PM
NULL
idx_PartitionTestTable_id_1431673117
2  1223672376  1431673117       1           2           0
62465       67256       66248                0
Mar  1 2010 11:19AM
NULL
idx_PartitionTestTable_name_1479673288
3  1223672376  1479673288       1           2           0
62721       69816       69386                0
Mar  1 2010  6:03PM
NULL
(6 rows affected)
1>

表PartitionTestTable是在其上的id列建了4个分区的分区表,它有2个索引。idx_PartitionTestTable_id对id列索引,idx_PartitionTestTable_name对name列索引。

我们就分析idx_PartitionTestTable_id这个索引吧。通过syspartitions表我们可以得到四个比较有用的 datoampage,indoampage, firstpage ,rootpage。分别表示数据对象分配页的页号,索引对象分配页的页号,

索引叶子层上的第一页,索引根部的页号。(堆表信息中的firstpage,rootpage意思有些不同。分别表示:数据页的第一个、最后一页。)

有:datoampage=0,indoampage=62465,firstpage= 67256,rootpage=66248.

对于indoampage索引对象分配页,可以这么查看。(PartitionTestTable的objid为: 1223672376)

dbcc listoam(4,1223672376,2)

3.可以看出索引idx_PartitionTestTable_id在14个对象分配页allocation page上的分配情况如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1> dbcc listoam(4,1223672376,2)
2> go
-----------------------------------------------------------------------------
Partition id: 1431673117     indid:   2 prevpg: 62465 nextpg: 62465
OAM pg cnt:      1      Entry cnt:         14
Row count information is not maintained for index pages.
Used pgs:      716      Unused pgs:        11
Attribute entries:       10
OAM status bits set:  (0x8000 (PG_OAMPG), 0x0008 (PG_OAMATTRIB), 0x0004
(PG_OAMSORT))
LAST SCANNED OAM PAGE:          0
ALLOCATION HINTS     :
62465          0          0          0
0          0          0          0
0          0          0          0
0          0          0
OAM pg #  1:      62465 has the following 14 entries (allocpg:used/unused):
[   0]      62464:  9/  6       63232: 24/  0       63744:  8/  0       64256:
0/  0
[   4]      64768: 16/  0       65024: 16/  0       65280: 16/  0       65536:
16/  0
[   8]      65792:152/  0       66048:240/  0       66304: 96/  0       66560:
48/  0
[  12]      66816: 40/  0       67072: 35/  5
There are 1 entries with zero used/unused values.
---- End of OAM chain for partition 1431673117 ----
DBCC execution completed. If DBCC printed error messages, contact a user with
System Administrator (SA) role.

(此处,暂时不解释以上结果中的情况!)

4.现在回到索引上,先从根部分析。rootpage=66248。

查看66248页上的16进制数据。

dbcc page(4,66248,1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
1> dbcc page(4,66248,1)
2> go
Page not found in Cache: default data cache.
Page read from disk.
BUFFER:
Buffer header for buffer 0x28288000 (Mass head)
page=0x28287000 bdnew=0x00000000 bdold=0x00000000 bhash=0x00000000
bmass_next=0x00000000 bmass_prev=0x00000000 bdbid=4
bvirtpg= [ 0x28288070 vpgdevno=5 vpvpn=132496 vdisk=0x21DE1CB4 ]
bmass_head=0x28288000 bmass_tail=0x28288000
bcache_desc=0x2828B3F0 (cache name='default data cache')
bpool_desc=0x00000000 bdbtable=0x00000000
Mass bkeep=0 Mass bpawaited=0 Mass btripsleft=0 Mass btripsleft_orig=0
bmass_size=4096 (4K pool) bunref_cnt=0
bmass_stat=0x0800 (0x00000800 (MASS_NOTHASHED))
bbuf_stat=0x0 (0x00000000)
Buffer blpageno=66248 bpg_size=4k Mass blpageno=66248 (Buffer slot #: 0)
bxls_pin=0x00000000 bxls_next=0x00000000 bspid=0
bxls_flushseq=0 bxls_pinseq=0 bcurrxdes=0x00000000
Latch and the wait queue:
Latch (address: 0x28288020)
latchmode: 0x0 (FREE_LATCH)
latchowner: 0
latchnoofowners: 0
latchwaitq: 0x00000000  latchwaitqt: 0x00000000
Latch wait queue:
PAGE HEADER:
Page header for page 0x28287000
pageno=66248 nextpg=0 prevpg=0 ptnid=1431673117  timestamp=0000 0040a817
lastrowoff=62 level=2 indid=2 freeoff=77 minlen=15
page status bits: 0x80 (0x0080 (PG_FIXED))
DATA:
Offset 32 - row length=15 # varlen cols=0 Child page ID=67258
28287020 (     0):  00be8301 00aff000 004100ba 060100    .........A.....
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
Offset 47 - row length=15 # varlen cols=0 Child page ID=65823
2828702F (     0):  00be8301 00aff000 0041001f 010100    .........A.....
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
Offset 62 - row length=15 # varlen cols=0 Child page ID=66990
2828703E (     0):  007b0703 00f0f200 009d00ae 050100    .{.............
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
OFFSET TABLE:
DBCC execution completed. If DBCC printed error messages, contact a user with
System Administrator (SA) role.
1>

此时,可以看出索引根部的级别level为2。 也就是说索引还有中间层level=1和叶子层level=0.

看第二行数据,

Offset 47 - row length=15 # varlen cols=0 Child page ID=65823
2828702F (     0):  00be8301 00aff000 0041001f 010100    .........A.....
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]

它的子页面号是:65823。

再来查看65823的页面数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
1> dbcc page(4,65823,1)
2> go
Page not found in Cache: default data cache.
Page read from disk.
BUFFER:
Buffer header for buffer 0x28288000 (Mass head)
page=0x28287000 bdnew=0x00000000 bdold=0x00000000 bhash=0x00000000
bmass_next=0x00000000 bmass_prev=0x00000000 bdbid=4
bvirtpg= [ 0x28288070 vpgdevno=5 vpvpn=131646 vdisk=0x21DE1CB4 ]
bmass_head=0x28288000 bmass_tail=0x28288000
bcache_desc=0x2828B3F0 (cache name='default data cache')
bpool_desc=0x00000000 bdbtable=0x00000000
Mass bkeep=0 Mass bpawaited=0 Mass btripsleft=0 Mass btripsleft_orig=0
bmass_size=4096 (4K pool) bunref_cnt=0
bmass_stat=0x0800 (0x00000800 (MASS_NOTHASHED))
bbuf_stat=0x0 (0x00000000)
Buffer blpageno=65823 bpg_size=4k Mass blpageno=65823 (Buffer slot #: 0)
bxls_pin=0x00000000 bxls_next=0x00000000 bspid=0
bxls_flushseq=0 bxls_pinseq=0 bcurrxdes=0x00000000
Latch and the wait queue:
Latch (address: 0x28288020)
latchmode: 0x0 (FREE_LATCH)
latchowner: 0
latchnoofowners: 0
latchwaitq: 0x00000000  latchwaitqt: 0x00000000
Latch wait queue:
PAGE HEADER:
Page header for page 0x28287000
pageno=65823 nextpg=66990 prevpg=67258 ptnid=1431673117  timestamp=0000
0040a817
lastrowoff=4052 level=1 indid=2 freeoff=4067 minlen=15
page status bits: 0x80 (0x0080 (PG_FIXED))
DATA:
Offset 32 - row length=15 # varlen cols=0 Child page ID=65822
28287020 (     0):  00be8301 00aff000 0041001e 010100    .........A.....
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
Offset 47 - row length=15 # varlen cols=0 Child page ID=66249
2828702F (     0):  002f8501 0039f100 003300c9 020100    ./...9...3.....
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
Offset 62 - row length=15 # varlen cols=0 Child page ID=66250
2828703E (     0):  00a08601 007bf100 00a700ca 020100    .....{.........
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
Offset 77 - row length=15 # varlen cols=0 Child page ID=66251
2828704D (     0):  00118801 00f3f000 00c800cb 020100    ...............
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
Offset 92 - row length=15 # varlen cols=0 Child page ID=66252
2828705C (     0):  00828901 00b0f000 00d100cc 020100    ...............
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
Offset 107 - row length=15 # varlen cols=0 Child page ID=66253
2828706B (     0):  00f38a01 003af100 00b500cd 020100    .....:.........
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]

此页面65823是索引的中间层level=1.看第一行的数据。

Offset 32 - row length=15 # varlen cols=0 Child page ID=65822
28287020 (     0):  00be8301 00aff000 0041001e 010100    .........A.....
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]

页面:66248上的第二行就是指向该行。

继续查看它的子页面上的数据,65822。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
1> dbcc page(4,65822,1)
2> go
Page not found in Cache: default data cache.
Page read from disk.
BUFFER:
Buffer header for buffer 0x28288000 (Mass head)
page=0x28287000 bdnew=0x00000000 bdold=0x00000000 bhash=0x00000000
bmass_next=0x00000000 bmass_prev=0x00000000 bdbid=4
bvirtpg= [ 0x28288070 vpgdevno=5 vpvpn=131644 vdisk=0x21DE1CB4 ]
bmass_head=0x28288000 bmass_tail=0x28288000
bcache_desc=0x2828B3F0 (cache name='default data cache')
bpool_desc=0x00000000 bdbtable=0x00000000
Mass bkeep=0 Mass bpawaited=0 Mass btripsleft=0 Mass btripsleft_orig=0
bmass_size=4096 (4K pool) bunref_cnt=0
bmass_stat=0x0800 (0x00000800 (MASS_NOTHASHED))
bbuf_stat=0x0 (0x00000000)
Buffer blpageno=65822 bpg_size=4k Mass blpageno=65822 (Buffer slot #: 0)
bxls_pin=0x00000000 bxls_next=0x00000000 bspid=0
bxls_flushseq=0 bxls_pinseq=0 bcurrxdes=0x00000000
Latch and the wait queue:
Latch (address: 0x28288020)
latchmode: 0x0 (FREE_LATCH)
latchowner: 0
latchnoofowners: 0
latchwaitq: 0x00000000  latchwaitqt: 0x00000000
Latch wait queue:
PAGE HEADER:
Page header for page 0x28287000
pageno=65822 nextpg=66249 prevpg=65821 ptnid=1431673117  timestamp=0000
0040a817
lastrowoff=4080 level=0 indid=2 freeoff=4091 minlen=11
page status bits: 0x82 (0x0080 (PG_FIXED), 0x0002 (PG_LEAF))
DATA:
Offset 32 - row length=11 # varlen cols=0 Data page RID=(61615, 65)
28287020 (     0):  00be8301 00aff000 004100             .........A.
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
Offset 43 - row length=11 # varlen cols=0 Data page RID=(61752, 198)
2828702B (     0):  00bf8301 0038f100 00c600             .....8.....
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
Offset 54 - row length=11 # varlen cols=0 Data page RID=(61818, 239)
28287036 (     0):  00c08301 007af100 00ef00             .....z.....
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]

还是分析页面上的第一行。索引叶子层直接指向了数据页面,某一页面上的某一行。

Offset 32 - row length=11 # varlen cols=0 Data page RID=(61615, 65)
28287020 (     0):  00be8301 00aff000 004100             .........A.
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]

继续往下,dbcc page(4,61615,1)找到第65行数据。

Offset 1072 - row ID=65 row length=16 # varlen cols=1
28287430 (     0):  0141be83 0100 1000 7a68616e 67020d08  .A......zhang...
28287440 (    16):
Row-Offset table for variable-length columns:
[<varcol number>, <offset from start of the row>, <varcol length>]
[1, 8, 5]

可以看出00be8301 00 aff000 004100中的be8301 00 和0141be83 01001000 7a68616e 67020d08中的

be83 0100 是一致的。也就是说索引中间层level=1是指向叶子层上的第一页。并且包含索引键的数据99262。

从16进制数据中分析出来,页61615第65行的数据为:id=99262,name='zhang'。

暂时就分析这么多。可能有些地方说的不太明白。见谅!

————————————————————————————————
—- 本文为andkylee个人原创,请在尊重作者劳动成果的前提下进行转载;
—- 转载务必注明原始出处 : http://www.dbainfo.net
—- 关键字:索引 存储结构 分析  非聚簇 index storage non-clustered
————————————————————————————————

在sybase表上建立聚集索引可以提高键列的检索速度。这是索引的主要功能所在。

可是,聚集索引对于统计表上的行数count(*)有没有改善呢? 答案是否定的。

请看我下面的测试代码!

建立一张临时表test3

1
create table test3(id int not null,name varchar(30) null)

向表中插入测试数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
insert into test3
select 1,'liu'
go
insert into test3
select 2,'zhang'
go
insert into test3
select 3,'wang'
go
insert into test3
select 4,'li'
go
循环插入
insert into test4
select count(*)+id,name from test4
go 18
1> select count(*) from  test4
2> go
-----------
524288
(1 row affected)
循环插入了524288条记录!

打开查询计划和统计查询计划时间的选项

1
2
3
4
set showplan on
go
set statistics time on
go

表上没有加任何索引的情况下。

select count(*) from test4 的查询计划为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
1> select count(*) from test4
2> go
QUERY PLAN FOR STATEMENT 1 (at line 1).
STEP 1
The type of query is SELECT.
2 operator(s) under root
|ROOT:EMIT Operator (VA = 2)
|
|   |SCALAR AGGREGATE Operator (VA = 1)
|   |  Evaluate Ungrouped COUNT AGGREGATE.
|   |
|   |   |SCAN Operator (VA = 0)
|   |   |  FROM TABLE
|   |   |  test4
|   |   |  Table Scan.
|   |   |  Forward Scan.
|   |   |  Positioning at start of table.
|   |   |  Using I/O Size 32 Kbytes for data pages.
|   |   |  With MRU Buffer Replacement Strategy for data pages.
Parse and Compile Time 0.
Adaptive Server cpu time: 0 ms.
-----------
524288
Execution Time 1.
Adaptive Server cpu time: 100 ms.  Adaptive Server elapsed time: 156 ms.
(1 row affected)

select count(1) from test4 的查询计划为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
1> select count(1) from test4
2> go
QUERY PLAN FOR STATEMENT 1 (at line 1).
STEP 1
The type of query is SELECT.
2 operator(s) under root
|ROOT:EMIT Operator (VA = 2)
|
|   |SCALAR AGGREGATE Operator (VA = 1)
|   |  Evaluate Ungrouped COUNT AGGREGATE.
|   |
|   |   |SCAN Operator (VA = 0)
|   |   |  FROM TABLE
|   |   |  test4
|   |   |  Table Scan.
|   |   |  Forward Scan.
|   |   |  Positioning at start of table.
|   |   |  Using I/O Size 32 Kbytes for data pages.
|   |   |  With MRU Buffer Replacement Strategy for data pages.
Parse and Compile Time 0.
Adaptive Server cpu time: 0 ms.
-----------
524288
Execution Time 1.
Adaptive Server cpu time: 100 ms.  Adaptive Server elapsed time: 220 ms.

可以看出,count(*) 和count(1) 的执行计划是相同的。都执行了表扫描。

由于表上没有任何索引可供使用,select count(id) 和 select count(name) 都是执行了表扫描。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
1> select count(id) from test4
2> go
QUERY PLAN FOR STATEMENT 1 (at line 1).
STEP 1
The type of query is SELECT.
2 operator(s) under root
|ROOT:EMIT Operator (VA = 2)
|
|   |SCALAR AGGREGATE Operator (VA = 1)
|   |  Evaluate Ungrouped COUNT AGGREGATE.
|   |
|   |   |SCAN Operator (VA = 0)
|   |   |  FROM TABLE
|   |   |  test4
|   |   |  Table Scan.
|   |   |  Forward Scan.
|   |   |  Positioning at start of table.
|   |   |  Using I/O Size 32 Kbytes for data pages.
|   |   |  With MRU Buffer Replacement Strategy for data pages.
Parse and Compile Time 0.
Adaptive Server cpu time: 0 ms.
-----------
524288
Execution Time 1.
Adaptive Server cpu time: 100 ms.  Adaptive Server elapsed time: 140 ms.
(1 row affected)
1> select count(name) from test4
2> go
QUERY PLAN FOR STATEMENT 1 (at line 1).
STEP 1
The type of query is SELECT.
2 operator(s) under root
|ROOT:EMIT Operator (VA = 2)
|
|   |SCALAR AGGREGATE Operator (VA = 1)
|   |  Evaluate Ungrouped COUNT AGGREGATE.
|   |
|   |   |SCAN Operator (VA = 0)
|   |   |  FROM TABLE
|   |   |  test4
|   |   |  Table Scan.
|   |   |  Forward Scan.
|   |   |  Positioning at start of table.
|   |   |  Using I/O Size 32 Kbytes for data pages.
|   |   |  With MRU Buffer Replacement Strategy for data pages.
Parse and Compile Time 0.
Adaptive Server cpu time: 0 ms.
-----------
524288
Execution Time 1.
Adaptive Server cpu time: 100 ms.  Adaptive Server elapsed time: 236 ms.
(1 row affected)
1>

下面考虑加入主键(聚集索引)pk_test4_id

1
2
alter table test4 add constraint pk_test4_id primary key (id)
go

再次执行select count(*) from test4 和 select count(1) from test4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
1> select count(*) from test4
2> go
QUERY PLAN FOR STATEMENT 1 (at line 1).
STEP 1
The type of query is SELECT.
2 operator(s) under root
|ROOT:EMIT Operator (VA = 2)
|
|   |SCALAR AGGREGATE Operator (VA = 1)
|   |  Evaluate Ungrouped COUNT AGGREGATE.
|   |
|   |   |SCAN Operator (VA = 0)
|   |   |  FROM TABLE
|   |   |  test4
|   |   |  Table Scan.
|   |   |  Forward Scan.
|   |   |  Positioning at start of table.
|   |   |  Using I/O Size 32 Kbytes for data pages.
|   |   |  With MRU Buffer Replacement Strategy for data pages.
Parse and Compile Time 0.
Adaptive Server cpu time: 0 ms.
-----------
524288
Execution Time 2.
Adaptive Server cpu time: 200 ms.  Adaptive Server elapsed time: 736 ms.
(1 row affected)
1> select count(1) from test4
2> go
QUERY PLAN FOR STATEMENT 1 (at line 1).
STEP 1
The type of query is SELECT.
2 operator(s) under root
|ROOT:EMIT Operator (VA = 2)
|
|   |SCALAR AGGREGATE Operator (VA = 1)
|   |  Evaluate Ungrouped COUNT AGGREGATE.
|   |
|   |   |SCAN Operator (VA = 0)
|   |   |  FROM TABLE
|   |   |  test4
|   |   |  Table Scan.
|   |   |  Forward Scan.
|   |   |  Positioning at start of table.
|   |   |  Using I/O Size 32 Kbytes for data pages.
|   |   |  With MRU Buffer Replacement Strategy for data pages.
Parse and Compile Time 0.
Adaptive Server cpu time: 0 ms.
-----------
524288
Execution Time 0.
Adaptive Server cpu time: 0 ms.  Adaptive Server elapsed time: 500 ms.
(1 row affected)
1>

由上可以看出,聚集索引对于select count(*) 几乎没有扫描影响。堆表和聚集索引表上的count是没有什么区别的,甚至于聚集索引表上的IO还要多2(这是因为多了两个聚集索引的数据块造成的)。其 实聚集索引并没有单独的保留所有索引列的信息,而只是将表中的行的物理顺序按照聚集索引列的顺序整理了一下,因此对聚集索 引的扫描和对堆表的扫描是一样的,没有什么本质上的区别。

添加id列上的非聚集索引idx_test4_id

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
1> create index idx_test4_id on test4(id)
2> go
1> sp_help test4
2> go
Name  Owner Object_type Create_date
----- ----- ----------- -------------------
test4 dbo   user table  Feb 25 2010  3:44PM
(1 row affected)
Column_name Type    Length Prec Scale Nulls Default_name Rule_name
Access_Rule_name Computed_Column_object Identity
----------- ------- ------ ---- ----- ----- ------------ ---------
---------------- ---------------------- ----------
id          int          4 NULL  NULL     0 NULL         NULL
NULL             NULL                            0
name        varchar     30 NULL  NULL     1 NULL         NULL
NULL             NULL                            0
Object has the following indexes
index_name   index_keys index_description index_max_rows_per_page
index_fillfactor index_reservepagegap index_created       index_local
------------ ---------- ----------------- -----------------------
---------------- -------------------- ------------------- ------------
pk_test4_id   id        clustered, unique                       0
0                    0 Feb 25 2010  4:04PM Global Index
idx_test4_id  id        nonclustered                            0
0                    0 Feb 25 2010  4:52PM Global Index
(2 rows affected)
index_ptn_name          index_ptn_seg
----------------------- -------------
pk_test4_id_1399673003  default
idx_test4_id_1399673003 default
(2 rows affected)
No defined keys for this object.
name  type       partition_type partitions partition_keys
----- ---------- -------------- ---------- --------------
test4 base table roundrobin              1 NULL
(1 row affected)
partition_name   partition_id pages row_count segment create_date
---------------- ------------ ----- --------- ------- -------------------
test4_1399673003   1399673003  2132    524288 default Feb 25 2010  4:04PM
Partition_Conditions
--------------------
NULL
Avg_pages   Max_pages   Min_pages   Ratio(Max/Avg)
Ratio(Min/Avg)
----------- ----------- ----------- ---------------------------
---------------------------
2132        2132        2132                    1.000000
1.000000
Lock scheme Allpages
The attribute 'exp_row_size' is not applicable to tables with allpages lock
scheme.
The attribute 'concurrency_opt_threshold' is not applicable to tables with
allpages lock scheme.
exp_row_size reservepagegap fillfactor max_rows_per_page identity_gap
ascinserts
------------ -------------- ---------- ----------------- ------------
-----------
0              0          0                 0            0
0
(1 row affected)
concurrency_opt_threshold optimistic_index_lock dealloc_first_txtpg
------------------------- --------------------- -------------------
0                     0                   0
(return status = 0)

此时再次执行select count(*) 和select count(1)。查询计划如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
1> select count(*) from test4
2> go
QUERY PLAN FOR STATEMENT 1 (at line 1).
STEP 1
The type of query is SELECT.
2 operator(s) under root
|ROOT:EMIT Operator (VA = 2)
|
|   |SCALAR AGGREGATE Operator (VA = 1)
|   |  Evaluate Ungrouped COUNT AGGREGATE.
|   |
|   |   |SCAN Operator (VA = 0)
|   |   |  FROM TABLE
|   |   |  test4
|   |   |  Index : idx_test4_id
|   |   |  Forward Scan.
|   |   |  Positioning at index start.
|   |   |  Index contains all needed columns. Base table will not be
read.
|   |   |  Using I/O Size 32 Kbytes for index leaf pages.
|   |   |  With MRU Buffer Replacement Strategy for index leaf pages.
Parse and Compile Time 0.
Adaptive Server cpu time: 0 ms.
-----------
524288
Execution Time 0.
Adaptive Server cpu time: 0 ms.  Adaptive Server elapsed time: 703 ms.
(1 row affected)
1> select count(1) from test4
2> go
QUERY PLAN FOR STATEMENT 1 (at line 1).
STEP 1
The type of query is SELECT.
2 operator(s) under root
|ROOT:EMIT Operator (VA = 2)
|
|   |SCALAR AGGREGATE Operator (VA = 1)
|   |  Evaluate Ungrouped COUNT AGGREGATE.
|   |
|   |   |SCAN Operator (VA = 0)
|   |   |  FROM TABLE
|   |   |  test4
|   |   |  Index : idx_test4_id
|   |   |  Forward Scan.
|   |   |  Positioning at index start.
|   |   |  Index contains all needed columns. Base table will not be
read.
|   |   |  Using I/O Size 32 Kbytes for index leaf pages.
|   |   |  With MRU Buffer Replacement Strategy for index leaf pages.
Parse and Compile Time 0.
Adaptive Server cpu time: 0 ms.
-----------
524288
Execution Time 1.
Adaptive Server cpu time: 100 ms.  Adaptive Server elapsed time: 93 ms.
(1 row affected)

可以看出查询引擎使用了非聚集索引idx_test4_id ,执行时间明显减少。因为计算行数这个操作对于全表扫描或是非聚集索引的扫描结果是一样的,而相对来说非聚集索引的数据量是肯定会比表的数据量小很多的,同样的做一次全部扫描所花费的IO也就要少很多了。

select count(id) 也是利用了非聚集索引 idx_test4_id。

结论:

count(*)和count(1)执行的效率是完全一样的。
如果是对特定的列做count的话建立这个列的非聚集索引能对count有很大的帮助。

————————————————————————————————————
——— 本文为andkylee个人原创,请在尊重作者劳动成果的前提下进行转载;
——— 转载务必注明原始出处 : http://www.dbainfo.net
——— 关键字: sybase 聚簇索引 非聚簇索引 查询计划 行数  count
————————————————————————————————————

这是一篇受密码保护的文章。您需要提供访问密码: