本文目录列表:
 
1、sys.sp_helptext存储的功能和效果
 
近来在研究sql server提供的现实可编程对象定义体的方法包括:sys.syscomments(视图)、sys.all_sql_modules(sys.sql_modules)(视图)、object_definition(函数)和sys.sp_helptext(存储)。针对以上方式的不同以后有时间在写成博文。本文主要研究了sys.sp_helptext的显示效果,感觉有些不太美好。先看该存储的现实效果如下图:
上图现在看没有什么的,那就将如下图的Text字段列内容复制放入单独的文件中再看其效果如下图:
上图我红色矩形框标注的地方了吧,每个行后都增加了char(13)和char(10)这两个字符导致的这样的显示效果,如果按照这个结果为基础进行变更,就增加了可编程对象定义的长度(主要是char(13)和char(10))。
 
2、重构sys.sp_helptext存储(命名为dbo.usp_helptext)提供直观的效果
 
发现了sys.sp_helptext的显示效果,我自己感觉不太满意,那么就重构嘛。重构后的代码如下:
 
if object_id(N'dbo.usp_helptext', 'P') IS NOT NULL
begin
drop procedure [dbo].[usp_helptext];
end
go create procedure [dbo].[usp_helptext]
(
@objname nvarchar(776)
,@columnname sysname = NULL
,@keeporiginal bit = NULL
)
as
begin
set nocount on set @keeporiginal = ISNULL(@keeporiginal, 1); declare @dbname sysname
,@objid int
,@BlankSpaceAdded int
,@BasePos int
,@CurrentPos int
,@TextLength int
,@LineId int
,@AddOnLen int
,@LFCR int --lengths of line feed carriage return
,@DefinedLength int /* NOTE: Length of @SyscomText is 4000 to replace the length of
** text column in syscomments.
** lengths on @Line, #CommentText Text column and
** value for @DefinedLength are all 255. These need to all have
** the same values. 255 was selected in order for the max length
** display using down level clients
*/
,@SyscomText nvarchar(4000)
,@Line nvarchar(255) select @DefinedLength = 255
select @BlankSpaceAdded = 0 /*Keeps track of blank spaces at end of lines. Note Len function ignores
trailing blank spaces*/
CREATE TABLE #CommentText
(LineId int
,Text nvarchar(255) collate catalog_default) /*
** Make sure the @objname is local to the current database.
*/
select @dbname = parsename(@objname,3)
if @dbname is null
select @dbname = db_name()
else if @dbname <> db_name()
begin
raiserror(15250,-1,-1)
return (1)
end /*
** See if @objname exists.
*/
select @objid = object_id(@objname)
if (@objid is null)
begin
raiserror(15009,-1,-1,@objname,@dbname)
return (1)
end -- If second parameter was given.
if ( @columnname is not null)
begin
-- Check if it is a table
if (select count(*) from sys.objects where object_id = @objid and type in ('S ','U ','TF'))=0
begin
raiserror(15218,-1,-1,@objname)
return(1)
end
-- check if it is a correct column name
if ((select 'count'=count(*) from sys.columns where name = @columnname and object_id = @objid) =0)
begin
raiserror(15645,-1,-1,@columnname)
return(1)
end
if (ColumnProperty(@objid, @columnname, 'IsComputed') = 0)
begin
raiserror(15646,-1,-1,@columnname)
return(1)
end declare ms_crs_syscom CURSOR LOCAL
FOR select text from syscomments where id = @objid and encrypted = 0 and number =
(select column_id from sys.columns where name = @columnname and object_id = @objid)
order by number,colid
FOR READ ONLY end
else if @objid < 0 -- Handle system-objects
begin
-- Check count of rows with text data
if (select count(*) from master.sys.syscomments where id = @objid and text is not null) = 0
begin
raiserror(15197,-1,-1,@objname)
return (1)
end declare ms_crs_syscom CURSOR LOCAL FOR select text from master.sys.syscomments where id = @objid
ORDER BY number, colid FOR READ ONLY
end
else
begin
/*
** Find out how many lines of text are coming back,
** and return if there are none.
*/
if (select count(*) from syscomments c, sysobjects o where o.xtype not in ('S', 'U')
and o.id = c.id and o.id = @objid) = 0
begin
raiserror(15197,-1,-1,@objname)
return (1)
end if (select count(*) from syscomments where id = @objid and encrypted = 0) = 0
begin
raiserror(15471,-1,-1,@objname)
return (0)
end declare ms_crs_syscom CURSOR LOCAL
FOR select text from syscomments where id = @objid and encrypted = 0
ORDER BY number, colid
FOR READ ONLY end /*
** else get the text.
*/
select @LFCR = 2
select @LineId = 1 open ms_crs_syscom fetch next from ms_crs_syscom into @SyscomText while @@fetch_status >= 0
begin
select @BasePos = 1
select @CurrentPos = 1
select @TextLength = LEN(@SyscomText) while @CurrentPos != 0
begin
--Looking for end of line followed by carriage return
select @CurrentPos = CHARINDEX(char(13)+char(10), @SyscomText, @BasePos) --If carriage return found
IF @CurrentPos != 0
begin
/*If new value for @Lines length will be > then the
**set length then insert current contents of @line
**and proceed.
*/
while (isnull(LEN(@Line),0) + @BlankSpaceAdded + @CurrentPos-@BasePos + @LFCR) > @DefinedLength
begin
select @AddOnLen = @DefinedLength-(isnull(LEN(@Line),0) + @BlankSpaceAdded)
insert #CommentText values
( @LineId,
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @AddOnLen), N''))
select @Line = NULL, @LineId = @LineId + 1,
@BasePos = @BasePos + @AddOnLen, @BlankSpaceAdded = 0
end -- 注释系统原来的使用如下修改
--select @Line = isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @CurrentPos-@BasePos + @LFCR), N'')
select @Line = isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @CurrentPos-@BasePos + (CASE @keeporiginal WHEN 1 THEN @LFCR ELSE 0 END)), N'')
select @BasePos = @CurrentPos+2
insert #CommentText values( @LineId, @Line )
select @LineId = @LineId + 1
select @Line = NULL
end
else
--else carriage return not found
begin
IF @BasePos <= @TextLength
begin
/*If new value for @Lines length will be > then the
**defined length
*/
while (isnull(LEN(@Line),0) + @BlankSpaceAdded + @TextLength-@BasePos+1 ) > @DefinedLength
begin
select @AddOnLen = @DefinedLength - (isnull(LEN(@Line),0) + @BlankSpaceAdded)
INSERT #CommentText VALUES
( @LineId,
isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @AddOnLen), N''))
select @Line = NULL, @LineId = @LineId + 1,
@BasePos = @BasePos + @AddOnLen, @BlankSpaceAdded = 0
end
select @Line = isnull(@Line, N'') + isnull(SUBSTRING(@SyscomText, @BasePos, @TextLength-@BasePos+1 ), N'')
if LEN(@Line) < @DefinedLength and charindex(' ', @SyscomText, @TextLength+1 ) > 0
begin
select @Line = @Line + ' ', @BlankSpaceAdded = 1
end
end
end
end FETCH NEXT from ms_crs_syscom into @SyscomText
end IF @Line is NOT NULL
INSERT #CommentText VALUES( @LineId, @Line ) select Text from #CommentText order by LineId CLOSE ms_crs_syscom
DEALLOCATE ms_crs_syscom DROP TABLE #CommentText return (0) -- sp_helptext
end
go

 

以上修改之处我已经标注了,其他的均来源sys.sp_helptext内容。
那就看看重构后的效果,如下图:
以上显示并看不出和sys.sp_helptext的有何不同,继续讲Text内容复制放入单独为文件中效果如下图:
上图红色矩形框就是显示的效果,下部分是为了对比,这部分可以使用如下代码显示器效果:
EXEC [sys].[sp_helptext]
@objname = N'sys.fn_get_sql' -- nvarchar(776)
,@columnname = NULL -- sysname
GO EXEC [dbo].[usp_helptext]
@objname = N'sys.fn_get_sql' -- nvarchar(776)
,@columnname = NULL -- sysname
,@keeporiginal = 1 -- bit
GO
 
注意:dbo.usp_helptext兼容了sys.sp_helptext的功能。
 
3、sys.sp_helptext和dbo.usp_helptext的限制以及解决方案
 
查阅了sys.sp_helptext的源码和其对应的联机帮助文档,发现其输出的字段列Text每行最多255个双字节字符,其输出到客户端最终的大小是4000个双字节字符,这个可以通过编码程序(例如VS程序读取获取等)突破这个限制。
 
其最大的缺点是每行255个,有可能遇到一行中一个分隔符前一部分属于前一个255个双字节字符,后一部分属于后一个255双字节字符的前部分。
具体的测试代码如下:
IF OBJECT_ID(N'[dbo].[uvm_MyTestView]', 'V') IS NOT NULL
BEGIN
DROP VIEW [dbo].[uvm_MyTestView];
END
GO CREATE VIEW [dbo].[uvm_MyTestView]
AS
SELECT
1 AS N'Col_1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111', 2 AS [Col_2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222]
GO
效果展示如下图:
上图显示的效果就是出现了截断。消除这个限制那就使用函数object_definition(不过这个也有缺点的,以后才单独讲解输出可编程对象定义的内容的区别)。
 
4、总结语
 
学习sql server提供的系统对象,发现他们写的代码真的很严密的,很多规范以及异常处理等,确实学到了很多的,不过也发现有些sql server的内部限制是不写出来的,如表记录行最大8060字节的限制以及可边长长度溢出到row-overflow索引分配类型的数据页后也在原来的记录行中增加24字节的指针这样也可有能超过行最大8060字节的限制。可能我看理论太少的缘故吧。唯有继续精进,代码编程还是要继续的,有时候sql server客户端输出的最大4000个双字节字符的限制可以通过编程的方式得到完本的解决。
 
昨天看到园中的一篇博文print、sp_helptext的限制与扩展通过PRINT输出分批次打印超长的字符串,也会遇到某个标识符截断的问题,因为PRINT每次到打印到客户端总增加了char(13)和char(10)这两个字符,这样就可能将一个标识符分割为前后两个批次。
 
5、参考清单列表
 

重构sql server的sys.sp_helptext存储的更多相关文章

  1. SQL Server 深入解析索引存储(下)

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/索引体系结构/非聚集索引 概述 非聚集索引与聚集索引具有相同的 B 树结构,它们之间的显著差别在于以下两点: 基础表的数据行不按非 ...

  2. SQL Server 堆表行存储大小(Record Size)

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 堆表行记录存储格式(Heap) 案例分析(Case) 参考文献(References) 二.背 ...

  3. SQL Server 深入解析索引存储(非聚集索引)

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/索引体系结构/非聚集索引 概述 非聚集索引与聚集索引具有相同的 B 树结构,它们之间的显著差别在于以下两点: 基础表的数据行不按非 ...

  4. SQL Server 2014 聚集列存储

    SQL Server 自2012以来引入了列存储的概念,至今2016对列存储的支持已经是非常友好了.由于我这边线上环境主要是2014,所以本文是以2014为基础的SQL Server 的列存储的介绍. ...

  5. SQL Server 深入解析索引存储(中)

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/索引体系结构/堆 概述 本篇文章是关于堆的存储结构.堆是不含聚集索引的表(所以只有非聚集索引的表也是堆).堆的 sys.parti ...

  6. SQL Server 深入解析索引存储(上)

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/索引体系结构/堆/聚集索引 概述 最近要分享一个课件就重新把这块知识整理了一遍出来,篇幅有点长,想要理解的透彻还是要上机实践. 聚 ...

  7. SQL Server索引 (原理、存储)聚集索引、非聚集索引、堆 <第一篇>

    一.存储结构 在SQL Server中,有许多不同的可用排列规则选项. 二进制:按字符的数字表示形式排序(ASCII码中,用数字32表示空格,用68表示字母"D").因为所有内容都 ...

  8. SQL Server 表和索引存储结构

    在上一篇文章中,我们介绍了SQL Server数据文件的页面类型,系统通过96个字节的头部信息和系统表从逻辑层面上将表的存储结构管理起来,具体到表的存储结构上,SQL Server引入对象.分区.堆或 ...

  9. SQL Server 深入解析索引存储(堆)

    标签:SQL SERVER/MSSQL SERVER/数据库/DBA/索引体系结构/堆 概述 本篇文章是关于堆的存储结构.堆是不含聚集索引的表(所以只有非聚集索引的表也是堆).堆的 sys.parti ...

随机推荐

  1. 关于Map集合

    Map接口实现Collection接口,是集合三大接口之一. Map接口在声明:public interface Map<K,V>;将键映射到值的对象,一个映射不能包含重复的键,每个键最多 ...

  2. 设置Android Studio启动时可选最近打开过的工程

    Android Studio启动时,默认会打开最近关闭的工程. 如果想Android Studio在启动时,打开欢迎界面(Welcome to Android Studio界面),则可以通过设置Set ...

  3. rails4.0 session activerecord

    Active Record Session Store A session store backed by an Active Record class. A default class is pro ...

  4. 一步步学习javascript基础篇(3):Object、Function等引用类型

    我们在<一步步学习javascript基础篇(1):基本概念>中简单的介绍了五种基本数据类型Undefined.Null.Boolean.Number和String.今天我们主要介绍下复杂 ...

  5. php杂记(一)

    1.require_once & require include() 函数会将指定的档案读入并且执行里面的程序 include_once() 与include相同,但只允许一次: requir ...

  6. .NET中异常处理的最佳实践(译)

    本文翻译自CodeProject上的一篇文章,原文地址. 目录 介绍 做最坏的打算 提前检查 不要信任外部数据 可信任的设备:摄像头.鼠标以及键盘 “写操作”同样可能失效 安全编程 不要抛出“new ...

  7. [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦

    [.net 面向对象程序设计进阶] (21) 反射(Reflection)(下)设计模式中利用反射解耦 本节导读:上篇文章简单介绍了.NET面向对象中一个重要的技术反射的基本应用,它可以让我们动态的调 ...

  8. .NET组件程序设计之线程、并发管理(二)

    .Net组件程序设计之线程.并发管理(二) 2.同步线程 手动同步 监视器 互斥 可等待事件 同步线程 所有的.NET组件都支持在多线程的环境中运行,可以被多个线程并发访问,如果没有线程同步,这样的后 ...

  9. OpenGL快问快答

    OpenGL快问快答 本文内容主要来自对(http://www.opengl.org/wiki/FAQ)的翻译,随机加入了本人的观点.与原文相比,章节未必完整,含义未必雷同,顺序未必一致.仅供参考. ...

  10. 今天Windows Azure Live to Code的分享

    今天参加了微软广州的Live to Code,晚上回公司OT写了封报告E-mail,也没让公司今天白出工资给我... 因为没有涉及到公司机密什么的,所以就拿出来跟大家分享一下. 首先要说明的是,在会议 ...