2009年4月1日星期三

如何扩展sybase数据库TEMPDB大小(转)

用sp_helpdb tempdb看了一下,原来的安装人员安装时master只有3M,tempdb在master设备上,只有1M多点,怪不得一个order就出问题。
解决的方法:
首先获取vdevno
use master
go
select max(convert(tinyint,substring(convert(binary(4),d.low),v.low,1)))+1
from master.dbo.sysdevices d,master.dbo.spt_values v
where v.type='E'and v.number=3
go
这里得到6
然后创建一个tempdb_dev设备:
disk init name="tempdb_dev", physname="d:\sybase\data\tempdb.dat", vdevno=6, size=262144
这里size是设备尺寸,单位是2K,一个页面2K,共创建500M的设备
接着扩展tempdb
alter database tempdb on tempdb_dev=500

2009年3月31日星期二

sybase分页查询思路

CREATE PROCEDURE GetDataByPage(
@SqlStr varchar(8000),
@PageSize int,
@CurrentPage int)
AS
DECLARE @FirstRec int, @LastRec int,@dt varchar(10)
BEGIN

SELECT @FirstRec = (@CurrentPage - 1) * @PageSize
SELECT @LastRec = (@CurrentPage * @PageSize + 1)

SELECT @dt= substring(convert(varchar,rand()),3,10)

SELECT @SqlStr = stuff(@SqlStr,charindex(' FROM ',upper(@SqlStr)),6,' INTO tempdb..Paging'+@dt+' FROM ')
EXECUTE (@SqlStr)

SELECT @SqlStr = 'ALTER TABLE tempdb..Paging'+@dt+' ADD RID numeric(10) IDENTITY PRIMARY KEY'
EXECUTE (@SqlStr)

SELECT @SqlStr = 'SELECT Count(*) From tempdb..Paging'+@dt
EXECUTE (@SqlStr)

SELECT @SqlStr = 'SELECT * FROM tempdb..Paging'+@dt+' WHERE RID >; '+convert(varchar,@FirstRec)+' and RID < '+convert(varchar,@LastRec)
EXECUTE (@SqlStr)

SELECT @SqlStr = 'DROP TABLE tempdb..Paging'+@dt
EXECUTE (@SqlStr)

END


另外一个小数据量时的简便方法:
select rowid=identity(12), * into #temptable1 from salesdetail
select * from #temptable1 where rowid<10>=1
注:当大数据量时将全表数据复制到临时表中是效率低下的

sybase中的临时表当用select into #table的形式时,是不记录日志的。速度非常快。
这点和oracle不同。算是sybase的一个feature.

用游标更好一些。
用临时表算法的空间复杂度是O(n),如果表很大或没有预存在Cache中,所用的I/O时间就非常可观了。
用游标定位到指定的页,空间复杂度应该是O(1),虽然游标遍历记录比直接用Select稍慢一点,但考虑到分页应用中,每次只读取一页的内容,所以这个时间性能上的损失可以忽略。


set rowcount 20
select * from salesdetail
set rowcount 0
注:此种方式不能设定查询的条件,如起始和结束位置、不能first、top、start at等。

一个简单的分页的存储过程:
create procedure test_p @ipage int, @num int as /* @ipage 页码, @num 每页的记录数 */
begin
declare @maxpages int, @rcount int /* @maxpages 最大页码 */
if @ipage>=100
select @maxpages=ceiling(count(*)/@num) from test
else
select @maxpages=100000
if @ipage<=@maxpages/2
begin
select @rcount=@ipage*@num
set rowcount @rcount
select id=identity(12),name,descs,ddd into #temptable1 from test order by id
select * from #temptable1 where id>(@ipage-1)*@num and id<= @ipage*@num
end else
begin
select @rcount=(@maxpages-@ipage+1)*@num
set rowcount @rcount
select id=identity(12),name,descs,ddd into #temptable2 from test order by id desc
select id,name, ddd,descs from #temptable2 where id>(@maxpages-@ipage)*@num and id<= (@maxpages-@ipage+1)*@num order by id desc
end
end

此存储过程的问题是:select into #temptable1需要大量的数据空间(tempdb),同时也会增加时间。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
版本更新:1.0.2
注意程序最后要加上set rowcount 0

create procedure splitpage @qry varchar(16384),@ipage int, @num int,@maxpages int = 5000 as
/*@qry SQL语句, @ipage 页数, @num 每页记录条数, @maxpages 最大查询页数 */
begin

declare @rcount int
declare @execsql varchar(16384)

if @ipage > @maxpages
begin
select '输入页数[' || convert(varchar,@ipage) || ']大于最大查询页数[' || convert (varchar,@maxpages) ||']'
return
end

select @rcount=@ipage*@num
set rowcount @rcount
set @execsql = stuff(@qry,charindex('select',@qry),6,'select sybid=identity(12),')
set @execsql = stuff(@execsql, charindex('from',@execsql),4,'into #temptable1 from')
set @execsql = @execsql || ' select * from #temptable1 where sybid>' || convert(varchar,(@ipage-1)*@num) || ' and sybid <= ' || convert(varchar,@ipage*@num)
execute (@execsql)
set rowcount 0
end

2009年3月12日星期四

网络小说推荐

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. 杯雪

2009年2月26日星期四

The key points for memory configuration

The key points for memeory configuration

1. 系统管理员需要决定ASE可以使用的内存总量,并设置'max memory'值;
2. 在系统启动时和系统运行时都可以通过设置'allocate max shared memory'值将ASE使用的内存动态收集到'max memory'大小;在某些系统上过大的shared memory segments会对系统表现造成不利影响,需要了解系统平台相关文档以决定'max memory'大小;
3. 配置其他影响内存分配的配置参数;
4. 'max memory'和'total logic memory'之间的差值可以用于procedure cache和data cache或者其他配置参数。
5. 当处理大字符串的数据查询时,ASE并不是静态的将数据缓冲分配到最大值,而是进行动态的分配。当有需要时,它将把buffer扩充到最大值,而不论其是否需要。这会造成处理大字符串查询时ASE系统性能有一个边际损失;
6. 一个表数据行超过1000列或者1个存储过程参数超过10000个,那么ASE需要为内部数据结构分配更多的内存。一些小任务的增加将会造成ASE性能表现的下降;
7. 动态的分配内存将会对ASE系统有轻微影响;
8. 当使用较大的logic page size时,每次ASE从硬盘获取与logic page size同样大小的数据块,这样会增加I/O吞吐量。

2009年2月25日星期三

Sybase ASE12.5内存配置(2)

ASE如何分配内存

1. logic page size
所有的数据库及数据库中的对象都采用同样的logic page size,logic page size在安装ASE时指定,可选项有2,4,8和16K。allocation page,object allocation map(OAM) page,data page,index page,text page等都建立在logic page之上。更大的logic page size值可以使你能创建更大的row,同时也可以使数据库读取数据时的效率更高,因为每一页更大,所包含的数据也更多。
logic page size是一个服务设定值,你无法对单个数据库进行单独设置,同时数据库中的每一行也不能存在于多个页之上。
extent: 数据库为对象分配空间时使用extent,每一个extent相当于8个logic page size大小。
更大的logic page size值也使得一些小的表的空间的最后一页所剩余的空间也更大。
数据库根据logic page size 不同,需要的最小磁盘空间数也不同,见下表:
2K 2MB
4K 4MB
8K 8MB
16K 16MB
内存分配的配置参数与logic page size不尽相同,无论logic page size设置多大,绝大多数内存分配参数采用2K,其中包括一下几个重要的内存配置参数:

2. 磁盘空间分配
磁盘空间分配以2K为单位。
3. logic page size不是默认时的处理
当logic page size设置为2K时,default data cache默认是8M大小,等于2048 buffers,而logic page size是16k时,如果仍然采用8M的default data cache,则只有256 buffers。如果buffer数量过小,在一个忙碌的系统中,buffers总是处于重写过程中,会导致系统整个运行速度变慢。所以当logic page size是默认的4倍时,你也需要将default data cache也设为默认的4倍。
4. Heap memory
Heap memory
是在启动时即已确定,用于当用户任务所耗堆内存过大时动态分配heap memory给用户任务使用,用户任务完成后将归还给heap memory。这样,可以减少预先设定给用户任务(user connections, worker processes)的堆内存,同时提高效率。
配置参数是heap memory per user, sp_configure 'heap memory per user',***(amount_of_memory),单位是byte,默认是4096bytes。
sp_configure 'heap memory per user', 10 给10个用户连接分配默认heap memory。
sp_configure 'heap memory per user', 0, "4K" 给每个用户分配4k的heap memory。
ASE初始化分配给heap memory总量是1M,不包括在刚才指定分配的内存中。初始的heap memory将会用于所有的user connections和worker processes。所以,以下两个参数与heap memory的分配密切相关:
number of user connections
number of worker processes
查看现有heap memory size使用命令:select @@heapmemsize
4.1. 计算ASE设置的heap memory size
((1024 * 1024) + (heap memory in bytes)* (number of user connections + number of worker processes) )
For example, if your server is configured for:
* heap memory per user : 4K
* number of user connectins : 25 (the default)
* number of worker processes : 25 (the default)
@@heapmemsize reports 1378304 bytes.
And the estimated value using the formula above, is:
((1024 X 1024) + (4 * 1024 * 50)) = 1253376
Now, if you increase the number of user connections, the size of the heap memory pool increases accordingly:
sp_configure 'user connections', 100
@@heapmemsize reports 1716224 bytes.
The estimated value in this case comes out to be:
((1024 * 1024) + (4 * 1024 * (100 + 25) ) = 1560576



5.

Sybase ASE内存分配(1)

今天同事为ASE分配内存后出现ASE服务无法启动的情况,观察ASE的errorlog发现报“os_create_region: Failed to get virtual memory information.”,确定是因为内存配置不合理造成的。通过google发现解决问题办法,如下:
修改$servername$.cfg
[Named Cache:default data cache]

cache size = DEFAULT

cache status = default data cache

cache replacement policy = DEFAULT

local cache partition number = D
EFAULT
修改cache size = DEFAULT

然后重新配置

没有修改ASE启动时的默认配置文件$servername$.cfg,而是将修改之前的ASE配置文件备份(如$servername$.033之类)修改名称替换掉当前不正确的cfg配置文件,重新启动后ASE恢复正常。

思考ASE启动失败的原因,在Sybase的《系统管理员教程》中,《14. 配置内存》中讲到如果ASE不能得到配置的内存,就可能无法启动。
那么如何正确的分配内存呢?
1. 确定计算机总的物流内存;
2. 从总的物流内存中减去操作系统和其他必备服务、软件所占用的内存;
3. 减去backup server 、Monitor Server和其他与ASE Server相关软件所耗用的内存;
4. 如果计算机非ASE专用,减去其他系统所需内存;比如X-window等客户应用程序;
5. 减去分配给additional network memory配置参数的任何内存;
剩下的内存即是ASE可用的总内存,可参考此值设置total memory的值。
我认为一个比较简便的方法是不启动ASE,而将Backup Server和Monitor Server以及其他必备服务、程序启动起来,观察计算机所剩内存,由此确定Total Memory。

当遇到以下情况时应该考虑修改total memory值:
1. 计算机RAM数量改变时;
2. 当计算机使用模式改变时;(不太明白?)
3. 如果为ASE的 addtional network memory分配了内存。

下图是Sybase ASE内存分配示意图。





















其中,过程高速缓存和数据高速缓存根据procedure cache percent进行分配。
在12.5版本中,sybase内存分配有所区别,请见图

2009年2月24日星期二

如何修改Syabse服务器端的默认字符集

如何修改Syabse服务器端的默认字符集
来源: 赛迪网 日期:2008-11-07 我要评论
在安装完Sybase后,很多人在使用isql或程序插入中文数据后发现,查询出的数据是乱码(中文字符全为?),这是因为客户端的字符集和服务端的字符集不一致造成的,Sybase默认安装后默认字符集为:iso_1。通常使用中文字符集在Sybase内是cp936。那么如何设置Sybase的字符
在安装完Sybase后,很多人在使用isql或程序插入中文数据后发现,查询出的数据是乱码(中文字符全为‘?’),这是因为客户端的字符集和服务端的字符集不一致造成的,Sybase默认安装后默认字符集为:iso_1。通常使用中文字符集在Sybase内是cp936。那么如何设置Sybase的字符集呢?修改方法如下:

以Windows操作系统Sybase15为例:

首先说明察看服务端字符集和客户端字符集的方法:

查看服务器端字符集:

在isql环境中执行:

1>; sp_helpsort

2>; go

查看客户端字符集:

在isql环境中执行:

1>; select @@client_csname

2>; go

修改服务端字符集方法:

假设sybase安装目录为$sybase$

◆1.转到$sybase$\ASE-15_0\bin目录

执行命令:charset -Usa -P binary.srt cp936

◆2.打开isql,执行下面的SQL查询出cp936对应的id

select id , name from syscharsets where name = 'cp936'

go

假设查询结果为171

执行下面语句设定默认字符集

sp_configure 'default char',171 --可能有误,以上面的查询结果为准

go

关闭ASE

shutdown

go

◆3.重新启动sybase服务两次(第一次启动会失败),启动服务。

如何扩展master数据库空间


如何扩展master数据库空间
master数据库只能扩展在master设备上.那么当master设备已经没有足够的空间可使用时,请按以下步骤操作:
(此操作过程是以UNIX操作系统为例.SYBASE安装路径为/sybase)
1.备份master数据库
启动backup server,进入isql环境执行:
1>dump database master to '/sybase/master.dump'
2>go
hut down SQL/ASE Server
1>shutdown
2>go

*shutdown时如果服务处于忙碌状态,可以使用shutdown with nowait命令直接关掉sybase sqlserver服务无须等待。

2.创建新的足够大的master设备
$buildmaster -d -ssize(size以2K为单位)
例:$buildmaster-d /sybase/data/master.dat –s102400

*buildmaster是老版本的执行程序,在ASE12.5及其以上版本是ASE-12_5/bin/sqlsrvr.exe。
3.修改RUN_servername文件
编辑RUN_server_name文件,-d参数指向新建的设备名。
4.单用户模式重启server
$startserver -f RUN_servername –m

*这是采用单用户模式启动服务。startsrv.exe在ASE-12_5\install\中。
5.执行installmaster脚本

*执行方法可以采用isql –Usa –P*** –S*** -iinstallmaster的方法。
6.由备份文件装载master数据库
1>load database master from '/sybase/master.dump'
2>go
7.修改sysdevices信息
sp_configure 'allow updates', 1
go
begin tran
go
update sysdevices set high = 102399 , phyname = 'e:\sybase\data\master_test.dat' where name = 'master'
go
(102399=200*512-1 master设备大小为200M)
commit tran
go

*采用isql登陆后执行。在修改时可能会出现master数据库日志已满的情况,这时只要执行dump transaction master with truncate_only截断日志即可执行余下步骤。
8.扩展master数据库
1>alter database master on master设备名称=size(此值以M为单位)
2>go
例:alter database master on master=10
将master数据库在master设备上扩展10M

*执行成功后,重启服务,并备份master设备。

2009年2月23日星期一

firefox插件

All-in-One Sidebar
Adblock Plus
AutoSlideshow
Browse Images
CoolPreviews
Delicious Bookmarks
DownThemAll!
Flashblock
Google Gears
Firebug
Google Toolbar
Google Preview
Greasemonkey
IE Tab
Image Zoom
Interclue
Linkification
MediaWrap
Save Images
SearchWith
Tab Mix Plus
TabRenamizer
Web Developer

2009年2月17日星期二

一个关于Java线程waite()、notifyAll()的例子

一个Java解决生产者-消费者同步问题的例子,很有参考价值的。

Java代码
  1. /////
  2. // ProducerConsumer.java
  3. //
  4. // 这是个很重要的Thread例子。需要注意的是:
  5. // wait() 必须在synchronized 函数或者代码块里面
  6. // wait()会让已经获得synchronized 函数或者代码块控制权的Thread暂时休息,并且丧失控制权
  7. // 这个时候,由于该线程丧失控制权并且进入等待,其他线程就能取得控制权,并且在适当情况下调用notifyAll()来唤醒wait()的线程。
  8. // 需要注意的是,被唤醒的线程由于已经丧失了控制权,所以需要等待唤醒它的线程结束操作,从而才能重新获得控制权。
  9. //
  10. // 所以wait()的确是马上让当前线程丧失控制权,其他的线程可以乘虚而入。
  11. //
  12. // 所以wait()的使用,必须存在2个以上线程,而且必须在不同的条件下唤醒wait()中的线程。
  13. //
  14. //
  15. // 以下的例子:
  16. // ProductStack 是一个生产者跟消费者共享的同步机制,这个机制决定了什么情况生产者要wait(),什么情况消费者要wait()
  17. // 可以把ProductStack看作一个产品仓库。当产品仓库满的时候,生产者线程需要wait(),从而放弃对产品仓库的控制。
  18. // 这个时候消费者线程就可以进来了而取得仓库的控制权。一旦消费者消费了产品,那么仓库就不满了。
  19. // 这个时候消费者线程就要notifyAll()生产者线程,让等待的生产者线程唤醒。
  20. // 但是生产者被唤醒后不能马上进行生产,因为它在wait()的时候已经丧失了对仓库的控制权,所以就需要等待消费者线程结束操作,
  21. // 才能重新取得仓库的控制权,再进行生产。
  22. //
  23. // 所以特别注意的是,notifyAll()并不是让当前线程马上让出控制权,而只是让其他wait()当中的线程唤醒而已,
  24. // 所以对不起,尽管我唤醒你,可你必须还是要等我用完仓库才能进来。这点必须清楚。
  25. //
  26. // 相反,仓库如果空的时候,消费者线程就会wait(),然后等待生产者线程来生产产品,生产者进程乘虚而入后,让生产者线程生产产品
  27. // 并且唤醒消费者线程。这个情况跟上面就类似了。
  28. //
  29. ///
  30. public class ProducerConsumer {
  31. public static void main(String[] args) {
  32. ProductStack ps = new ProductStack();
  33. Producer p = new Producer(ps, "生产者1");
  34. Consumer c = new Consumer(ps, "消费者1");
  35. new Thread(p).start();
  36. new Thread(c).start();
  37. }
  38. }
  39. class Product {
  40. int id;
  41. private String producedBy = "N/A";
  42. private String consumedBy = "N/A";
  43. // 构造函数,指明产品ID以及生产者名字。
  44. Product(int id, String producedBy) {
  45. this.id = id;
  46. this.producedBy = producedBy;
  47. }
  48. // 消费,需要指明消费者名字
  49. public void consume(String consumedBy) {
  50. this.consumedBy = consumedBy;
  51. }
  52. public String toString() {
  53. return "Product : " + id + ", produced by " + producedBy
  54. + ", consumed by " + consumedBy;
  55. }
  56. public String getProducedBy() {
  57. return producedBy;
  58. }
  59. public void setProducedBy(String producedBy) {
  60. this.producedBy = producedBy;
  61. }
  62. public String getConsumedBy() {
  63. return consumedBy;
  64. }
  65. public void setConsumedBy(String consumedBy) {
  66. this.consumedBy = consumedBy;
  67. }
  68. }
  69. // 这个class就是仓库,是生产者跟消费者共同争夺控制权的同步资源
  70. class ProductStack {
  71. int index = 0;
  72. Product[] arrProduct = new Product[6];
  73. // push使用来让生产者放置产品的
  74. public synchronized void push(Product product) {
  75. // 如果仓库满了
  76. while (index == arrProduct.length) // 这里本来可以用if(),但是如果catch
  77. // exception会出问题,让满的index越界
  78. {
  79. try {
  80. // here, "this" means the thread that is using "push"
  81. // so in this case it's a producer thread instance.
  82. // the BIG difference between sleep() and wait() is, once
  83. // wait(),
  84. // the thread won't have the lock anymore
  85. // so when a producer wait() here, it will lost the lock of
  86. // "push()"
  87. // While sleep() is still keeping this lock
  88. // Important: wait() and notify() should be in "synchronized"
  89. // block
  90. System.out.println(product.getProducedBy() + " is waiting.");
  91. // 等待,并且从这里退出push()
  92. wait();
  93. } catch (InterruptedException e) {
  94. e.printStackTrace();
  95. }
  96. }
  97. System.out.println(product.getProducedBy() + " sent a notifyAll().");
  98. // 因为我们不确定有没有线程在wait(),所以我们既然生产了产品,就唤醒有可能等待的消费者,让他们醒来,准备消费
  99. notifyAll();
  100. // 注意,notifyAll()以后,并没有退出,而是继续执行直到完成。
  101. arrProduct[index] = product;
  102. index++;
  103. System.out.println(product.getProducedBy() + " 生产了: " + product);
  104. }
  105. // pop用来让消费者取出产品的
  106. public synchronized Product pop(String consumerName) {
  107. // 如果仓库空了
  108. while (index == 0) {
  109. try {
  110. // here will be the consumer thread instance will be waiting ,
  111. // because empty
  112. System.out.println(consumerName + " is waiting.");
  113. // 等待,并且从这里退出pop()
  114. wait();
  115. } catch (InterruptedException e) {
  116. e.printStackTrace();
  117. }
  118. }
  119. System.out.println(consumerName + " sent a notifyAll().");
  120. // 因为我们不确定有没有线程在wait(),所以我们既然消费了产品,就唤醒有可能等待的生产者,让他们醒来,准备生产
  121. notifyAll();
  122. // 注意,notifyAll()以后,并没有退出,而是继续执行直到完成。
  123. // 取出产品
  124. index--;
  125. Product product = arrProduct[index];
  126. product.consume(consumerName);
  127. System.out.println(product.getConsumedBy() + " 消费了: " + product);
  128. return product;
  129. }
  130. }
  131. class Producer implements Runnable {
  132. String name;
  133. ProductStack ps = null;
  134. Producer(ProductStack ps, String name) {
  135. this.ps = ps;
  136. this.name = name;
  137. }
  138. public void run() {
  139. for (int i = 0; i < 20; i++) {
  140. Product product = new Product(i, name);
  141. ps.push(product);
  142. try {
  143. Thread.sleep((int) (Math.random() * 200));
  144. } catch (InterruptedException e) {
  145. e.printStackTrace();
  146. }
  147. }
  148. }
  149. }
  150. class Consumer implements Runnable {
  151. String name;
  152. ProductStack ps = null;
  153. Consumer(ProductStack ps, String name) {
  154. this.ps = ps;
  155. this.name = name;
  156. }
  157. public void run() {
  158. for (int i = 0; i < 20; i++) {
  159. Product product = ps.pop(name);
  160. try {
  161. Thread.sleep((int) (Math.random() * 1000));
  162. } catch (InterruptedException e) {
  163. e.printStackTrace();
  164. }
  165. }
  166. }
  167. }