今天上午去面拭,面拭官问了我一些问题,其中包括这个问题,他明显表露出对我的不屑,没有诚意的人我也不想去。我不是另外再写一篇文章哗众取宠(存储过程与嵌入式Sql语句的比较), 只是想完全的表达一下自己的想法。我想先提个建议,不知道合不合适?我注册博客园也一年多了,每天浏览一下博客园的文章似乎是我现在每天必做的一件事,也 看过很多人对文章对评论所发表的个人见解,但是我觉得,仔细揣摩一下一些人的评论,会发现有很多人会给别人一种别样的感觉,怎么说呢,骨子里有一种" 傲”,或者是“浮”,大家静下心来想一想,我的文章或者评论是想帮助别人或者通过帮助别人的同时提高自己呢?还是想证明自己?在这里,我是真诚的,没有造 作的意思,说的不对,各位批评。关于这个木刀兄的问题,我想表达以下自己的观点,只对事不对人,谁也别生气。
首先,我觉得没有绝对的谁对谁错的问题,只要是自己最熟悉的方式就一定是最好的方法,下面我只是站在我自己的角度以共性的方式来说明我的观点.
(1)数据库系统是支撑软件,本质上说,他是一个应用程序,从应用的角度来说,他是一个存储器,但是无论如何都是这个应用程序在执行操作数据。在 vs2005下,会发现存储过程是在服务器对象的目录下,这说明他是一个数据库对象,他是在这个应用程序下的一个本地对象,所以本地对象对本地资源的访问 没有性能损失或者说很小。既然数据库系统是应用程序,它就必然存在于一个进程或者线程中。同样,我门的Web应用程序也会存在于一个进程或者线程中,凡是 在Web应用程序中的执行逻辑,譬如sql语句,要想跟数据库系统中的数据或者对象交互,那都是进程与进程或者线程与线程的通讯问题,而进程间或者线程间 通讯肯定是有性能损失的。这是很多问题的关键所长.这是从单个机器上来说,如果从许多机器上来访问一台机器上的程序,网络流量的问题是首要考虑的问题,认 为left语句等业务逻辑不应该写在存储过程等理解都是错误的,至于说数据库是影响性能最大的一层,不应该把更多的业务逻辑放在数据库中,这种推理不正 确。最大的性能损失是在数据库连接上,存储过程的业务逻辑是一次编译终身受用,而sql语句的业务逻辑每个终端用户都要执行一次,从宏观上说,根本不是一 个等价比。
(2)效率和性能问题。关于sql语句的执行效率与存储过程差别不大,很多人都认同,而且认为编译时间可以忽略,理由是从自己电脑上测试以下差别不大。为 什么不测试一个读取20万条数据的差别呢?即使是测试这么多的数据,时间差我也认为不是很大。这个时间差大约相当于现如今我们的高性能的计算机二十万次重 复计算一条数据的问题,这当然是轻而一举。但是这跟本不是实际的场景,实际的场景是我们的程序被二十万台电脑执行一条数据而不是让一台电脑执行二十万条数 据,要想测试这种差别,为什么不使用一下压力测试工具?编译时间不能被忽略,因为不是一台电脑的编译而是二十万台电脑编译的问题,这是首先要确定的一点。 其实,我觉得还有一个问题,是sql逻辑语句段所不能媲美的。当我们从业务逻辑访问存储过程的结果集后,这个结果集是被缓存的,至于是基于表级别的还是行 级别的,是缓存依赖还是其他等等这个问题不重要,重要的是这些数据库软件肯定对缓存这一点有所保障。如果说sql逻辑片段也能够缓存的话,那只能是页面级 缓存,相比于数据级缓存,不可同日而语。另外,顺便提一下,在server2000下,执行两次同一sql语句,不能保证取出来的结果集是同一结果集,只 是在大多数情况下,也许99%的情况下,我门看不到这中差异把了。不过不用担心,server2005能够保证。后边举一小例。
(3)至于说安全性,可扩展性,可管理性,认为从某一程度上来说,sql语句片段要比存储过程更有优势,我想这是始末倒置了。至于安全性,先不说sql语 句注入,存储过程提供的更强大的权限角色控制等,但从软件的角度来说,你觉得我门自己开发的应用程序更能保证安全呢还是这些几千专家开发的数据库软件更能 保证安全呢?至于可扩展性等等,能否从这个角度来看,假设数据库软件仅仅是一个象文件系统一样的存储系统,当我门写了大量的sql语句后发现不好维护了, 所以,我门会尝试利用面向对象的思想来封装这些语句为对象,等我门有了很多对象以后,我门会想能不能象企业库那样具有可视化的界面来操作呢?我门所看到的 存储过程,我觉得就是一种图形化的便于扩展和维护的对象。如果非要争辩sql语句与存储过程的可扩展可维护的优劣,那只能上升到面向过程与面向对象熟优熟 劣的问题。我只是从宏观上来辩解,我也并不认为面向对象就一定更有优势,语言都是死的,人是活的,只要是自己最熟悉的,那就是最好的。
(四)如果说存储过程写到几百几千不好维护,那么不知道sql语句要写到多少?其实一个数据库中的存储过程最多也就到百的数量级,想一想就知道呀,二十张 表也就百来个存储过程把。如果说我的业务需求需要几百张表,那么我会反问,为什么非要把它门放在一个数据库中呢?有经验的人都会知道,一个数据库存储大量 数据是有瓶颈的,我的意见是存储在多个数据库实体中。
下面是我认为在Server2005下实现分页的最好写法,而且也建议分页逻辑写在存储过程中,这是数据层次上的分页,它的好处我已经罗嗦了很多了。
首先,我觉得没有绝对的谁对谁错的问题,只要是自己最熟悉的方式就一定是最好的方法,下面我只是站在我自己的角度以共性的方式来说明我的观点.
(1)数据库系统是支撑软件,本质上说,他是一个应用程序,从应用的角度来说,他是一个存储器,但是无论如何都是这个应用程序在执行操作数据。在 vs2005下,会发现存储过程是在服务器对象的目录下,这说明他是一个数据库对象,他是在这个应用程序下的一个本地对象,所以本地对象对本地资源的访问 没有性能损失或者说很小。既然数据库系统是应用程序,它就必然存在于一个进程或者线程中。同样,我门的Web应用程序也会存在于一个进程或者线程中,凡是 在Web应用程序中的执行逻辑,譬如sql语句,要想跟数据库系统中的数据或者对象交互,那都是进程与进程或者线程与线程的通讯问题,而进程间或者线程间 通讯肯定是有性能损失的。这是很多问题的关键所长.这是从单个机器上来说,如果从许多机器上来访问一台机器上的程序,网络流量的问题是首要考虑的问题,认 为left语句等业务逻辑不应该写在存储过程等理解都是错误的,至于说数据库是影响性能最大的一层,不应该把更多的业务逻辑放在数据库中,这种推理不正 确。最大的性能损失是在数据库连接上,存储过程的业务逻辑是一次编译终身受用,而sql语句的业务逻辑每个终端用户都要执行一次,从宏观上说,根本不是一 个等价比。
(2)效率和性能问题。关于sql语句的执行效率与存储过程差别不大,很多人都认同,而且认为编译时间可以忽略,理由是从自己电脑上测试以下差别不大。为 什么不测试一个读取20万条数据的差别呢?即使是测试这么多的数据,时间差我也认为不是很大。这个时间差大约相当于现如今我们的高性能的计算机二十万次重 复计算一条数据的问题,这当然是轻而一举。但是这跟本不是实际的场景,实际的场景是我们的程序被二十万台电脑执行一条数据而不是让一台电脑执行二十万条数 据,要想测试这种差别,为什么不使用一下压力测试工具?编译时间不能被忽略,因为不是一台电脑的编译而是二十万台电脑编译的问题,这是首先要确定的一点。 其实,我觉得还有一个问题,是sql逻辑语句段所不能媲美的。当我们从业务逻辑访问存储过程的结果集后,这个结果集是被缓存的,至于是基于表级别的还是行 级别的,是缓存依赖还是其他等等这个问题不重要,重要的是这些数据库软件肯定对缓存这一点有所保障。如果说sql逻辑片段也能够缓存的话,那只能是页面级 缓存,相比于数据级缓存,不可同日而语。另外,顺便提一下,在server2000下,执行两次同一sql语句,不能保证取出来的结果集是同一结果集,只 是在大多数情况下,也许99%的情况下,我门看不到这中差异把了。不过不用担心,server2005能够保证。后边举一小例。
(3)至于说安全性,可扩展性,可管理性,认为从某一程度上来说,sql语句片段要比存储过程更有优势,我想这是始末倒置了。至于安全性,先不说sql语 句注入,存储过程提供的更强大的权限角色控制等,但从软件的角度来说,你觉得我门自己开发的应用程序更能保证安全呢还是这些几千专家开发的数据库软件更能 保证安全呢?至于可扩展性等等,能否从这个角度来看,假设数据库软件仅仅是一个象文件系统一样的存储系统,当我门写了大量的sql语句后发现不好维护了, 所以,我门会尝试利用面向对象的思想来封装这些语句为对象,等我门有了很多对象以后,我门会想能不能象企业库那样具有可视化的界面来操作呢?我门所看到的 存储过程,我觉得就是一种图形化的便于扩展和维护的对象。如果非要争辩sql语句与存储过程的可扩展可维护的优劣,那只能上升到面向过程与面向对象熟优熟 劣的问题。我只是从宏观上来辩解,我也并不认为面向对象就一定更有优势,语言都是死的,人是活的,只要是自己最熟悉的,那就是最好的。
(四)如果说存储过程写到几百几千不好维护,那么不知道sql语句要写到多少?其实一个数据库中的存储过程最多也就到百的数量级,想一想就知道呀,二十张 表也就百来个存储过程把。如果说我的业务需求需要几百张表,那么我会反问,为什么非要把它门放在一个数据库中呢?有经验的人都会知道,一个数据库存储大量 数据是有瓶颈的,我的意见是存储在多个数据库实体中。
下面是我认为在Server2005下实现分页的最好写法,而且也建议分页逻辑写在存储过程中,这是数据层次上的分页,它的好处我已经罗嗦了很多了。
ALTER PROCEDURE GetProductsOnDepartmentPromotion
(@DepartmentID INT,
@DescriptionLength INT,
@PageNumber INT,
@ProductsPerPage INT,
@HowManyProducts INT OUTPUT)
AS
-- declare a new TABLE variable
DECLARE @Products TABLE
(RowNumber INT,
ProductID INT,
Name VARCHAR(50),
Description VARCHAR(5000),
Price MONEY,
Image1FileName VARCHAR(50),
Image2FileName VARCHAR(50),
OnDepartmentPromotion BIT,
OnCatalogPromotion BIT)
-- populate the table variable with the complete list of products
--特别注意一下Row_number()函数,用自己的序列号保证结果集的唯一行,并能提供很多便利之处。
INSERT INTO @Products
SELECT ROW_NUMBER() OVER (ORDER BY ProductID) AS Row,
ProductID, Name, SUBSTRING(Description, 1, @DescriptionLength) + '' AS Description,
Price, Image1FileName, Image2FileName, OnDepartmentPromotion, OnCatalogPromotion
FROM
(SELECT DISTINCT Product.ProductID, Product.Name,
SUBSTRING(Product.Description, 1, @DescriptionLength) + '' AS Description,
Price, Image1FileName, Image2FileName, OnDepartmentPromotion, OnCatalogPromotion
FROM Product INNER JOIN ProductCategory
ON Product.ProductID = ProductCategory.ProductID
INNER JOIN Category
ON ProductCategory.CategoryID = Category.CategoryID
WHERE Product.OnDepartmentPromotion = 1
AND Category.DepartmentID = @DepartmentID
) AS ProductOnDepPr
-- return the total number of products using an OUTPUT variable
SELECT @HowManyProducts = COUNT(ProductID) FROM @Products
-- extract the requested page of products
SELECT ProductID, Name, Description, Price, Image1FileName,
Image2FileName, OnDepartmentPromotion, OnCatalogPromotion
FROM @Products
WHERE RowNumber > (@PageNumber - 1) * @ProductsPerPage
AND RowNumber <= @PageNumber * @ProductsPerPage
(@DepartmentID INT,
@DescriptionLength INT,
@PageNumber INT,
@ProductsPerPage INT,
@HowManyProducts INT OUTPUT)
AS
-- declare a new TABLE variable
DECLARE @Products TABLE
(RowNumber INT,
ProductID INT,
Name VARCHAR(50),
Description VARCHAR(5000),
Price MONEY,
Image1FileName VARCHAR(50),
Image2FileName VARCHAR(50),
OnDepartmentPromotion BIT,
OnCatalogPromotion BIT)
-- populate the table variable with the complete list of products
--特别注意一下Row_number()函数,用自己的序列号保证结果集的唯一行,并能提供很多便利之处。
INSERT INTO @Products
SELECT ROW_NUMBER() OVER (ORDER BY ProductID) AS Row,
ProductID, Name, SUBSTRING(Description, 1, @DescriptionLength) + '' AS Description,
Price, Image1FileName, Image2FileName, OnDepartmentPromotion, OnCatalogPromotion
FROM
(SELECT DISTINCT Product.ProductID, Product.Name,
SUBSTRING(Product.Description, 1, @DescriptionLength) + '' AS Description,
Price, Image1FileName, Image2FileName, OnDepartmentPromotion, OnCatalogPromotion
FROM Product INNER JOIN ProductCategory
ON Product.ProductID = ProductCategory.ProductID
INNER JOIN Category
ON ProductCategory.CategoryID = Category.CategoryID
WHERE Product.OnDepartmentPromotion = 1
AND Category.DepartmentID = @DepartmentID
) AS ProductOnDepPr
-- return the total number of products using an OUTPUT variable
SELECT @HowManyProducts = COUNT(ProductID) FROM @Products
-- extract the requested page of products
SELECT ProductID, Name, Description, Price, Image1FileName,
Image2FileName, OnDepartmentPromotion, OnCatalogPromotion
FROM @Products
WHERE RowNumber > (@PageNumber - 1) * @ProductsPerPage
AND RowNumber <= @PageNumber * @ProductsPerPage