被MSSQL耍了



------
1.建表,报警告,行最大大小超过8060,INSERT和UPDATE可能失败

2.插入数据,报超过8060,插入失败

3.用ALTER TABLE ALTER COLUMN COL_NAME VARCHAR(MAX)把所有字符串列全改成VARCHAR(MAX),其它列长度加起来共320

4.插入数据,报超过8060,插入失败


就这样,被华丽丽的刷了,虽然现在已经解决了,但还是郁闷。


第一个详细解释原因的给250技术分,谨以此分献给MS
------
你人品不好,楼主给分吧
------
连问题都没看懂的就不用答了,我只想知道这个结果的原理,以及这样是否合理。

明天再公布答案。
------
求真相
------
VAHCHAR(MAX)不是到溢出块了么?还能限制?
------
额..http://blog.csdn.net/happyflystone/article/details/4923803
看一下是这个原因不,鸭子
------
当表中具有可变长度列(如 nvarchar 或 varbinary)时,所有列的总最大长度之和不能大于 8,060 字节。如果每一行中数据的总长度不超过 8,060 字节,就仍可以向表中插入行。解决办法,把较大长度的列改类型为text或者ntext. 

------
.... 额,环境是》?
------
没看懂,占位学习
------
引用 11 楼 的回复:

当表中具有可变长度列(如 nvarchar 或 varbinary)时,所有列的总最大长度之和不能大于 8,060 字节。如果每一行中数据的总长度不超过 8,060 字节,就仍可以向表中插入行。解决办法,把较大长度的列改类型为text或者ntext.

------
引用 12 楼 的回复:

.... 额,环境是》?

------
恭喜鸭子,贺喜鸭子
------
不是你被mssql耍了,是你把mssql耍了。

修改列的话,实际上原来的列还是存在的 ,会在列的最后加一个列,那么一行的数据就会更大。

sql 2005中,varchar,nvarchar等 单列的数据必须小于8000,但是合并宽度可以大于8060字节。
text是作为blob数据进行存放
------
引用 15 楼 的回复:
引用 11 楼 的回复:

当表中具有可变长度列(如 nvarchar 或 varbinary)时,所有列的总最大长度之和不能大于 8,060 字节。如果每一行中数据的总长度不超过 8,060 字节,就仍可以向表中插入行。解决办法,把较大长度的列改类型为text或者ntext.

参看第三步,已经用第三步的方法把所有字符串都改成VARCHAR(MAX)了,也改成过TEXT,效果一样的。

------
引用 15 楼 的回复:
引用 11 楼 的回复:

当表中具有可变长度列(如 nvarchar 或 varbinary)时,所有列的总最大长度之和不能大于 8,060 字节。如果每一行中数据的总长度不超过 8,060 字节,就仍可以向表中插入行。解决办法,把较大长度的列改类型为text或者ntext.

参看第三步,已经用第三步的方法把所有字符串都改成VARCHAR(MAX)了,也改成过TEXT,效果一样的。

------
ms sql当中,数据记录不能跨页存储,每条记录所占的空间不能超过8060字节,也就是表中1条记录的所有字段的长度和不能超过8060。一般解决办法是把一些长度比较大的字段设为text或者image类型。
你自己检查一下总长度吧。另外是不是建了约束、触发器等对象,这些也会占些空间。
比如
create table t_Users(a varchar(8000),b varchar(8000)) 

因为a+b=16000的长度已经超过了一条记录的最大存储长度8060 
这种情况下,表可以正常地被创建,只要你存储/修改数据时 
datalength(a)+datalength(b)<8060 
那你的操作就不会有任何问题. 
否则,操作就会失败
------
引用楼主 的回复:
1.建表,报警告,行最大大小超过8060,INSERT和UPDATE可能失败

2.插入数据,报超过8060,插入失败

3.用ALTER TABLE ALTER COLUMN COL_NAME VARCHAR(MAX)把所有字符串列全改成VARCHAR(MAX),其它列长度加起来共320

4.插入数据,报超过8060,插入失败


就这样,被华丽丽的刷了,虽然现在已经解决了,……

------
引用 25 楼 的回复:
引用楼主 的回复:
1.建表,报警告,行最大大小超过8060,INSERT和UPDATE可能失败

2.插入数据,报超过8060,插入失败

3.用ALTER TABLE ALTER COLUMN COL_NAME VARCHAR(MAX)把所有字符串列全改成VARCHAR(MAX),其它列长度加起来共320

4.插入数据,报超过8060,插入失败


就这样,被华丽丽的刷了……

------
关注
------
哎,连菜鸟级别都算不上的我,压根就看不懂啊,纯观望···求学习
------
没明白问题
------
公布我的答案

之前已经有不少大大分析过ALTER TABLE ALTER COLUMN的实现方法是在页中加列,问题就是出在这

我前三步都是正常的,问题是在第四步。

当已经把列改成VARCHAR(MAX)后,看起来表中所有列的长度(加上指针)不超过400,但同样报长度超长的错误,也就是说,看起来我的修改根本没达到我要的效果,即用溢出页存储大数据。

解决方法很简单,ALTER COLUMN后,直接DROP TABLE再CREATE TABLE就可以了。

原因没仔细分析,初步推断原因可能有两个,一是由于是在页中新加列,长数据进来没有进到溢出页,而是存储在了原列中,导致存储失败。另一个是更改列长度后,某些统计信息没更新,导致分析插入语句时认为无法插入这么长的数据。

综上,25楼最接近答案,我也是改完后又查了一列全部列的长度合,确定很短后才考虑到删表重建的。
下面就是大家讨论一下,这种情况算不算BUG。
------
这个东西搞得这么神秘?
------
神秘点好
------
有时候确实发现,当更新列的类型之后,长度和类型,没有变。要等一会才能正常插入数据。(极少数情况下)
------
楼主,我提个建议,你要想把问题讨论深刻,明白真相,你就把你的测试数据贴上来,证明你说的情况怎么发生的,csdn上有很多高手,要解释你的问题根本不是问题,就算你要精确到每个字节
------
mark 一下,回头研究
------
引用 34 楼 的回复:
楼主,我提个建议,你要想把问题讨论深刻,明白真相,你就把你的测试数据贴上来,证明你说的情况怎么发生的,csdn上有很多高手,要解释你的问题根本不是问题,就算你要精确到每个字节

------
25楼分析得不错
------
看来我只好接250了


把char 改 varchar

------
这个问题跟此帖有无关系呢?
http://topic.csdn.net/u/20111107/09/4d3a2d90-33eb-49f2-9710-f119bd04ee62.html
------
实际中,当字符换比较长的时候 超过50 基本上就没有定长了,所以就不要char 了
低于50的就算不定长,用char 也比较好,这样让页的长度更稳定。
------
我表示题目真的没有看懂- -。。。
------
引用 46 楼 的回复:
只对于2005 或者以上版本

1、警告是因为有char列存在,因为char 是定长的,所以他会去计算,varchar 是非定长的只要实际存储的数据没有超过这个上限, 就不会有问题,别且这个8060 不会去考虑varchar,搞成0来统计

SQL code

create table test1
(
a varchar(1000),
b char(8000),
……

------
引用 34 楼 的回复:
楼主,我提个建议,你要想把问题讨论深刻,明白真相,你就把你的测试数据贴上来,证明你说的情况怎么发生的,csdn上有很多高手,要解释你的问题根本不是问题,就算你要精确到每个字节

------
引用 52 楼 的回复:
引用 34 楼 的回复:
楼主,我提个建议,你要想把问题讨论深刻,明白真相,你就把你的测试数据贴上来,证明你说的情况怎么发生的,csdn上有很多高手,要解释你的问题根本不是问题,就算你要精确到每个字节

是啊,这么点破事儿弄得神神秘秘的,有装逼嫌疑。再说即便是bug,SQL Server每个补丁都会解决十几个甚至几十个bug,有啥稀奇的。

------
呵呵,关注下!
------
有收获,学习了。
------
楼主 财大气粗 !!

被耍耍 。。。。 也好 !
------

11楼不是妞吗? 咋变成哥了

引用 21 楼 的回复:

引用 15 楼 的回复:
引用 11 楼 的回复:

当表中具有可变长度列(如 nvarchar 或 varbinary)时,所有列的总最大长度之和不能大于 8,060 字节。如果每一行中数据的总长度不超过 8,060 字节,就仍可以向表中插入行。解决办法,把较大长度的列改类型为text或者ntext.

参看第三步,已经用第三步的方法把所有字符串都改成VARCHAR(MAX)了,也……

------
被耍啊 悲剧 搞得我也被耍
------
凡是数据表的行标题超过8086的表设计都是垃圾,信不信由你!
------
电脑速度不快用MSSQL的路过,暂时没做过什么大的数据库,不知道这个情况,学习了
------
都是菜鸟
------
引用 50 楼 的回复:

引用 46 楼 的回复:
只对于2005 或者以上版本

1、警告是因为有char列存在,因为char 是定长的,所以他会去计算,varchar 是非定长的只要实际存储的数据没有超过这个上限, 就不会有问题,别且这个8060 不会去考虑varchar,搞成0来统计

SQL code

create table test1
(
a varchar(1000),
b char……

------
非常好,说的很好,讲的很详细,拿来看看。
------
我的电脑非常卡,用不了。
------
观摩下讨论
------
学习中,加油!
------
最近长度为8000个字节,,超出肯定报错
------

------
引用 28 楼 的回复:

哎,连菜鸟级别都算不上的我,压根就看不懂啊,纯观望···求学习

------
学习一下了!
------
学习者
------
以前遇到过,改text类型改不了,最后新建一张表,导入数据了事。
应该不算BUG吧,虽然不好理解,但还是可以用道理解释得通,这只能怪文档中“每行最多包括 8,060 个字节”的描述容易让人误解。
------
学习了
------
MS没有帅你,你应该按下F1,新版本的SQL Server有解决这些问题的,但永远跟不上问题的出现
------
围观学习中。
------
学习!
------
将varchar(max)换成 text
------
mark!学习了。
------
楼主大人,学习学习
------

------

------
已经看不懂...学习 围观
------
引用 86 楼 的回复:


------
[Quote=引用 66 楼 的回复:]
1、当然坑定有char 或者nchar 了 如果是varchar nvarchar 是不会有这种警告的,不信你试试
2、SSMS的界面操作实际上它也是生成了sql 语句去执行的
3、这个问题恐怕设计之初就要避免或者解决,一开始插入数据就会报错和警告,难道不修改等海量数据了再说?

1、T-SQL的数据类型只有char nchar nvarchar nvarchar?int datetime这些不是么,如果用这些楼主会算错长度?你这个逻辑上就不混淆,说肯定是char,原因是如果是varchar nvarchar就不会有这种警告...

2、没说SSMS操作不是生成sql去执行,而是说SSMS的操作是组合的语句,那不是原本意义上的修改表的操作,你也说了它是先删除在创建的方法,这种方法本身就是不高效的,它只能面对那些不懂的修改细节,只求结果的用户,所以这种方法是用户层面的,作为操作数据库来说,这种方式远远不够,也不合适,只是让你操作简单一点而已。

3、有多少问题是设计之初就能考虑得到的?也许你接手的时候就是一个这样的表或者数据库,很多时候你只能调整优化,而不是推翻重来
------
我太菜了,没懂……
------
原理其实很简单,这与sqlserver数据库底层引擎相关,一般数据库都有一个自己的基本数据块大小,这个块大小一般都是理想记录大小,比如oracle的就是8k.这样,每次找查找一行的时候就只要一次IO就可以了,而且存储的时候,如果一行大小不够一个记录块,就会空着,会保持一个数据块只存放一个行的数据,如果一行数据大于一个记录块,当然会占有多个数据块。一般来讲,对于大数据类型是会单独存放这个列的,不会放在同一个记录中,这也就是为什么有大数据列的时候,如果select *会比较的原因,因为每行都需要2次以上的IO.一行(一个记录)尽量保持在一个数据库记录块中,不仅对于查询,更新很方便,对于建立索引也非常方便,这个道理大家可以思考一下,如果一个记录跨块得情况下,或者更极端点,行与行窜记录块的情况下,效率都是非常低的。
------
压根没看懂 好深奥的感觉
------
学习一下
------
呵呵 学习一次啊
------
mark 一下,回头研究
------
這是資料庫每筆記錄的容量上限,(如每筆記錄真的有這樣大)只可將資料庫來升級解決,否則應使用varchar or nvarchar type,來減小每筆記錄所需容量。

------
微软的强大。
------
楼主,是一行里字段(除了页类型的字段,但楼主的字段都是varchar)宽度加起来超过8060了哦,楼主还是仔细查一下看,是不是有某行的所有字段宽度加起来超过了8060,注意是一行的所有字段(除了页类型的字段)宽度加起来哦。
桂ICP备07017180号