我一直在一个表中记录昂贵的运行查询及其查询计划,以便我们监控性能趋势并确定需要优化的区域。
然而,现在已经到了查询计划占用太多空间的地步(因为我们针对每个查询存储整个计划)。
因此,我试图通过将 QueryPlanHash 和 QueryPlan 提取到另一个表来规范化现有数据。
CREATE TABLE QueryPlans
(
QueryPlanHash VARBINARY(25),
QueryPlan XML,
CONSTRAINT PK_QueryPlans PRIMARY KEY
(
QueryPlanHash
)
);
Run Code Online (Sandbox Code Playgroud)
由于query_plan_hashin的定义sys.dm_exec_query_stats是一个二进制字段(并且我会定期插入新数据),因此我使用VARBINARY了新表中的数据类型。
但是,下面的插入失败了...
INSERT INTO QueryPlans
( QueryPlanHash, QueryPlan )
SELECT queryplanhash, queryplan
FROM
(
SELECT
p.value('(./@QueryPlanHash)[1]', 'varchar(20)') queryplanhash,
QueryPlan,
ROW_NUMBER() OVER (PARTITION BY p.value('(./@QueryPlanHash)[1]', 'varchar(20)') ORDER BY DateRecorded) rownum
FROM table
CROSS APPLY QueryPlan.nodes('/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple[@QueryPlanHash]') t(p)
) data
WHERE rownum = 1
Run Code Online (Sandbox Code Playgroud)
....有错误
Implicit conversion from data type varchar to varbinary is …Run Code Online (Sandbox Code Playgroud) 我们有一个数据库,在varbinary(max)类型的字段中存储了大量数据。在某些时候,我们可以清除大多数行的数据,但不是全部。我们的计划是使该字段可以为空,并在不再需要数据时将其清空。一旦我们这样做,我们希望减少数据库的大小。实现这一目标的最佳方法是什么?
如果没有使用当前设置回收空间的好方法,我的一个想法是将该数据字段移动到只有两列的单独表:主表的键和数据字段。然后我们可以简单地删除不再需要的行。(然后进行某种收缩。)但是,这比简单地使现有字段可空要困难得多。
注意:我实际上不太关心使数据库文件变小,但我确实关心新释放的空间变得可重用。
超过 90% 的数据库大小是这一字段。我已经在 3TB 了。
我的数据库中有一个表,我们用作文件存储,文件本身存储在一个varbinary列中,直到最近这一切似乎都运行良好,我们注意到该表的一个实例基本上“卡住”了插入语句.
检查sys.dm_os_waiting_tasks显示插入语句触发了统计更新,并且此统计更新花费了很长时间。(17 分钟)。
这是我们发现运行的语句:
SELECT StatMan([SC0], [LC0]) FROM
(SELECT TOP 100 PERCENT CONVERT([varbinary](200),
SUBSTRING ([Data], 1, 100)++substring([Data],
case when LEN([Data])<=200 then 101 else
LEN([Data])-99 end, 100)) AS [SC0],
datalength([Data]) AS [LC0]
FROM [FileSystem].[FileData] WITH
(READUNCOMMITTED) ORDER BY [SC0] ) AS _MS_UPDSTATS_TBL
Run Code Online (Sandbox Code Playgroud)
该表中大约有 2000 行,如下所示:
CREATE TABLE [FileSystem].[FileData]
(
[Id] [uniqueidentifier] NOT NULL CONSTRAINT [DF__FileData__Id__09DE7BCC] DEFAULT (newsequentialid()),
[Data] [varbinary] (max) NULL,
[FileHash] [nvarchar] (4000) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[FileSize] [bigint] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] …Run Code Online (Sandbox Code Playgroud) 似乎 SQL Server 认为 0x 和 0x00 相等:
SELECT CASE WHEN 0x = 0x00 THEN 1 ELSE 0 END
Run Code Online (Sandbox Code Playgroud)
这输出1.
如何获得真正的二进制位对位比较行为?另外,两个值被认为相等的确切规则(var)binary是什么?
还要注意以下行为:
--prints just one of the values
SELECT DISTINCT [Data]
FROM (VALUES (0x), (0x00), (0x0000)) x([Data])
--prints the obvious length values 1, 2 and 3
SELECT DATALENGTH([Data]) AS [DATALENGTH], LEN([Data]) AS [LEN]
FROM (VALUES (0x), (0x00), (0x0000)) x([Data])
Run Code Online (Sandbox Code Playgroud)
问题的背景是我正在尝试对二进制数据进行重复数据删除。我需要GROUP BY二进制数据,而不仅仅是比较两个值。我很高兴我什至注意到了这个问题。
请注意,它HASHBYTES不支持 LOB。我也想找到一个更简单的解决方案。
这对我来说真的是一个令人困惑的话题。
我可以理解 BLOB 是什么,我可以轻松使用它。我能理解 FILESTREAM 是什么。我可以轻松地在数据库中实现,我可以备份数据库并使用为存储这些文件而创建的文件夹来恢复它。像这样的事情,我想,我能理解。
我不明白的是:
.PDF仅使用数据库中的 VARBINARY(MAX) 列插入(例如)与将其存储.PDF在 FILESTREAM 数据库中有什么区别。我知道 BLOB varbinary(max).PDF是在数据库内部。如果我物理删除.PDF,我仍然可以使用存储在 varbinary(MAX) 列中的值来恢复它吗?
当我在.PDF文件流中插入这个文件时,我可以在文件夹中看到它(为文件组创建的那个),如果我插入 100 个文件,我可以在文件流文件夹中看到 100 个文件,但是当我运行DELETE FROM并删除 100 行时数据库,我仍然可以在文件流文件夹中看到这些文件。为什么会发生这种情况?我认为,为了保持一致性,这些文件也会被删除。
对于这两种情况,在.PDFBLOBVARBINARY(MAX)或 FILESTREAM 中插入文件后,我还需要原始文件吗?因为它在数据库中,所以我可以很容易地恢复它。
我以 .PDF 为例
我可以使用和实施这两种方法,但我仍然不清楚它们会发生什么。对我来说,它是一样的,但是一个存储在数据库之外,另一个存储在数据库内。
由于客户端应用程序将 PDF 文件存储为 varbinary,我有一个现有的旧表,大小约为 180GB。我希望能够在创建新解决方案时使用 GZIP 压缩所有行的该列以帮助节省空间(我希望有一种方法可以在 SQL 中执行此操作,而不必为此编写客户端代码)。我看到该COMPRESS方法可用于 Sql Server 2016,但我需要一个适用于 2008 的解决方案。任何想法将不胜感激。
如果数据像这样每 3 个字节分割,是否可以将其适应更新查询,该更新查询必须寻找 3 个字节或 (0x000000) 的空闲序列,并用新序列替换它?问题是强制转换/替换无法处理未定义的数据(即 0x00)。varbinary 数据每 3 个字节划分 -> data(3bytes 长)data(3bytes 长)。
DECLARE @YourTable table
(
Id INT PRIMARY KEY,
Val VARBINARY(50)
)
INSERT @YourTable
VALUES (1, 0x0329000414000B14000C14000D0F00177800224600467800473C00550F00000000000000000000000000),
(2, 0x0329002637000B14000C14000D0F00177800224600467800473C00550F00000000000000000000000000);
SELECT Id, Triplet
FROM @YourTable T
JOIN (VALUES (1),(4),(7),(10),(13),(16),(19),(22),(25),(28),(31),(34),(37),(40),(43),(46),(49)) Nums(Num) ON Num <= DATALENGTH(T.Val)
CROSS APPLY (VALUES (SUBSTRING(T.Val, Num, 3))) V(Triplet)
WHERE Triplet = 0x000000 and DATALENGTH(Triplet) = 3
Run Code Online (Sandbox Code Playgroud)
我尝试过的:
UPDATE x
set x.column = CAST(REPLACE(x.column, 0x000000, 0xFFFFFF) AS VARBINARY)
from Table as x
Run Code Online (Sandbox Code Playgroud)
仅当列不包含数据时才有效。
UPDATE x …Run Code Online (Sandbox Code Playgroud) 我将图像文件作为 XML 数据接收,图像的每个字节都是一个带有十进制值的节点,例如对于这个示例 .png 文件,
,我得到的xml是:
DECLARE @xml XML = N'<?xml version="1.0" encoding="utf-16" standalone="yes"?>
<XmlData>
<Element>
<id>Test</id>
<image>
<Element>137</Element><Element>80</Element><Element>78</Element><Element>71</Element><Element>13</Element><Element>10</Element><Element>26</Element><Element>10</Element><Element>0</Element><Element>0</Element><Element>0</Element><Element>13</Element><Element>73</Element><Element>72</Element><Element>68</Element><Element>82</Element><Element>0</Element><Element>0</Element><Element>0</Element><Element>20</Element><Element>0</Element><Element>0</Element><Element>0</Element><Element>20</Element><Element>8</Element><Element>6</Element><Element>0</Element><Element>0</Element><Element>0</Element><Element>141</Element><Element>137</Element><Element>29</Element><Element>13</Element><Element>0</Element><Element>0</Element><Element>0</Element><Element>4</Element><Element>103</Element><Element>65</Element><Element>77</Element><Element>65</Element><Element>0</Element><Element>0</Element><Element>177</Element><Element>143</Element><Element>11</Element><Element>252</Element><Element>97</Element><Element>5</Element><Element>0</Element><Element>0</Element><Element>0</Element><Element>9</Element><Element>112</Element><Element>72</Element><Element>89</Element><Element>115</Element><Element>0</Element><Element>0</Element><Element>14</Element><Element>193</Element><Element>0</Element><Element>0</Element><Element>14</Element><Element>193</Element><Element>1</Element><Element>184</Element><Element>145</Element><Element>107</Element><Element>237</Element><Element>0</Element><Element>0</Element><Element>0</Element><Element>24</Element><Element>116</Element><Element>69</Element><Element>88</Element><Element>116</Element><Element>83</Element><Element>111</Element><Element>102</Element><Element>116</Element><Element>119</Element><Element>97</Element><Element>114</Element><Element>101</Element><Element>0</Element><Element>112</Element><Element>97</Element><Element>105</Element><Element>110</Element><Element>116</Element><Element>46</Element><Element>110</Element><Element>101</Element><Element>116</Element><Element>32</Element><Element>52</Element><Element>46</Element><Element>48</Element><Element>46</Element><Element>54</Element><Element>252</Element><Element>140</Element><Element>99</Element><Element>223</Element><Element>0</Element><Element>0</Element><Element>0</Element><Element>108</Element><Element>73</Element><Element>68</Element><Element>65</Element><Element>84</Element><Element>56</Element><Element>79</Element><Element>99</Element><Element>24</Element><Element>5</Element><Element>184</Element><Element>192</Element><Element>114</Element><Element>32</Element><Element>254</Element><Element>14</Element><Element>196</Element><Element>30</Element><Element>96</Element><Element>30</Element><Element>21</Element><Element>192</Element><Element>126</Element><Element>32</Element><Element>254</Element><Element>15</Element><Element>196</Element><Element>9</Element><Element>96</Element><Element>30</Element><Element>21</Element><Element>192</Element><Element>48</Element><Element>55</Element><Element>80</Element><Element>7</Element><Element>136</Element><Element>29</Element><Element>208</Element><Element>240</Element><Element>121</Element><Element>32</Element><Element>6</Element><Element>25</Element><Element>216</Element><Element>142</Element><Element>36</Element><Element>6</Element><Element>195</Element><Element>34</Element><Element>64</Element><Element>140</Element><Element>23</Element><Element>128</Element><Element>98</Element><Element>19</Element><Element>164</Element><Element>153</Element><Element>88</Element><Element>60</Element><Element>27</Element><Element>136</Element><Element>241</Element><Element>130</Element><Element>213</Element><Element>64</Element><Element>12</Element><Element>242</Element><Element>34</Element><Element>50</Element><Element>126</Element><Element>15</Element><Element>196</Element><Element>32</Element><Element>205</Element><Element>215</Element><Element>145</Element><Element>196</Element><Element>96</Element><Element>56</Element><Element>3</Element><Element>136</Element><Element>73</Element><Element>6</Element><Element>32</Element><Element>141</Element><Element>32</Element><Element>3</Element><Element>71</Element><Element>147</Element><Element>13</Element><Element>249</Element><Element>128</Element><Element>234</Element><Element>6</Element><Element>250</Element><Element>0</Element><Element>113</Element><Element>5</Element><Element>16</Element><Element>43</Element><Element>128</Element><Element>121</Element><Element>163</Element><Element>0</Element><Element>1</Element><Element>24</Element><Element>24</Element><Element>0</Element><Element>127</Element><Element>60</Element><Element>48</Element><Element>197</Element><Element>152</Element><Element>102</Element><Element>243</Element><Element>130</Element><Element>0</Element><Element>0</Element><Element>0</Element><Element>0</Element><Element>73</Element><Element>69</Element><Element>78</Element><Element>68</Element><Element>174</Element><Element>66</Element><Element>96</Element><Element>130</Element>
</image>
</Element>
</XmlData>'
Run Code Online (Sandbox Code Playgroud)
在二进制中:
SELECT * FROM OPENROWSET(BULK 'C:\test.png', SINGLE_BLOB) AS q;
==========
BulkColumn
----------
0x89504E470D0A1A0A0000000D49484452000000140000001408060000008D891D0D0000000467414D410000B18F0BFC6105000000097048597300000EC100000EC101B8916BED0000001874455874536F667477617265007061696E742E6E657420342E302E36FC8C63DF0000006C49444154384F631805B8C07220FE0EC41E601E15C07E20FE0FC409601E15C030375007881DD0F079200619D88E2406C322408C17806213A499583C1B88F182D5400CF222327E0FC420CDD791C4603803884906208D200347930DF980EA06FA007105102B8079A300011818007F3C30C59866F3820000000049454E44AE426082
Run Code Online (Sandbox Code Playgroud)
如何从 xml 中检索图像文件作为 varbinary?
不久前我也问过类似的问题,所以我尝试了以下查询,但结果二进制数据不正确:
SELECT r.c.value('id[1]', 'varchar(50)') AS id,
CONVERT(VARBINARY(MAX), (SELECT (t.u.value('.','tinyint')) FROM r.c.nodes('image/Element') AS t(u) FOR XML PATH(''))) AS image
FROM @xml.nodes('/XmlData/Element') AS r(c);
=============
id image
-------------
Test 0x31003300370038003000370038003700310031003300310030003200360031003000300030003000310033003700330037003200360038003800320030003000300032003000300030003000320030003800360030003000300031003400310031003300370032003900310033003000300030003400310030003300360035003700370036003500300030003100370037003100340033003100310032003500320039003700350030003000300039003100310032003700320038003900310031003500300030003100340031003900330030003000310034003100390033003100310038003400310034003500310030003700320033003700300030003000320034003100310036003600390038003800310031003600380033003100310031003100300032003100310036003100310039003900370031003100340031003000310030003100310032003900370031003000350031003100300031003100360034003600310031003000310030003100310031003600330032003500320034003600340038003400360035003400320035003200310034003000390039003200320033003000300030003100300038003700330036003800360035003800340035003600370039003900390032003400350031003800340031003900320031003100340033003200320035003400310034003100390036003300300039003600330030003200310031003900320031003200360033003200320035003400310035003100390036003900390036003300300032003100310039003200340038003500350038003000370031003300360032003900320030003800320034003000310032003100330032003600320035003200310036003100340032003300360036003100390035003300340036003400310034003000320033003100320038003900380031003900310036003400310035003300380038003600300032003700310033003600320034003100310033003000320031003300360034003100320032003400320033003400350030003100320036003100350031003900360033003200320030003500320031003500310034003500310039003600390036003500360033003100330036003700330036003300320031003400310033003200330037003100310034003700310033003200340039003100320038003200330034003600320035003000300031003100330035003100360034003300310032003800310032003100310036003300300031003200340032003400300031003200370036003000340038003100390037003100350032003100300032003200340033003100330030003000300030003000370033003600390037003800360038003100370034003600360039003600310033003000
Run Code Online (Sandbox Code Playgroud) 由于代码测试不佳(不是我的!),我最终得到了一个包含 319 个VARBINARY(MAX)字段、两个DATETIME字段和两个UNIQUEIDENTIFIER字段的表。显然这并不理想,但它应该仍然在 SQL Server 可以处理的行大小的限制内。
据我了解,VARBINARY(MAX)它作为一个 24 字节的指针存储在表上,指向行外存储。24 * 319 = 7656字节,加上其他四个字段= 7704个字节,所以我只是在我可以投入一排的限制。
这一切都很好,直到代码开始将数据插入到这个表中。在与消息崩溃之前它有 6 行:
无法创建大小为 8345 的行,该行大于允许的最大行大小 8060。语句已终止。
这是非常令人费解的,因为任何行都不应该比其他行大(至少在行上)。我已经编写了表格的脚本,它看起来不错。我确实注意到它是用创建的,ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]尽管我不确定会产生什么效果。
有谁知道这里可能会发生什么,更重要的是我如何解决它?
这是用于创建数据库的代码,以及插入命令
CREATE DATABASE MyBigDB;
GO
USE [MyBigDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[Autogenerated table with really big data](
[Primary_key] [uniqueidentifier] NULL,
[A Foreign key] [uniqueidentifier] NULL,
[Created] [datetime] NULL,
[Updated] [datetime] NULL, …Run Code Online (Sandbox Code Playgroud) 在 SQL Server 2005 和 2008 R2 中,我调用了一个存储过程,该存储过程的 out 参数定义为varbinary(max). 根据 .out 参数返回 10020 字节DATALENGTH。
但是,如果我尝试定义大于 8000 字节的 varbinary,例如 varbinary(10000),则 SQL Server 会出错。例如
The size (10000) given to the type 'varbinary' exceeds the maximum allowed for any data type (8000).
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?SQL Server 如何返回超过数据类型允许的字节数?SQL Server 是否在幕后使用其他一些数据类型来保存 > 8000 字节?
我们有一个 SQL 2016 数据库,其中有一个 19 亿行的表,其中有一个 varbinary(255) 列,我们用它来存储同一个表中 nvarchar(2000) 字段的 HashBytes。
我们在 varbinary 字段上有一个非聚集索引,并且我们的索引维护脚本每 2-3 天对此执行一次 REORGANIZE。但这需要10多个小时才能完成。
有什么办法可以提高varbinary字段索引维护的速度吗?
index sql-server varbinary sql-server-2016 index-maintenance
我正在尝试进行一个遍历 varbinary 数据的查询。问题是我无法真正完成我想要实现的目标。关于该列,您应该了解的是 varbinary(50) ,并且出现的模式没有特定的书写顺序,这意味着每个前缀可以是任何位置,只要它有 3 个字节(0x000000) 第一个字节是前缀,第二个和第三个是值数据我想检查它是否在我喜欢的范围内。所有的数据都是这样写的。
我尝试过的:
DECLARE @t TABLE (
val VARBINARY(MAX)
)
INSERT INTO @t SELECT 0x00000100000000000000000000000000000000000000000000000000
INSERT INTO @t SELECT 0x00001000000000000000000000000000000000000000000000000000
INSERT INTO @t SELECT 0x00010000000000000000000000000000000000000000000000000000
INSERT INTO @t SELECT 0x00100000000000000000000000000000000000000000000000000000
INSERT INTO @t SELECT 0x00000f00000000000000000000000000000000000000000000000000
declare @pattern varbinary(max)
declare @pattern2 varbinary(max)
set @pattern = 0x0001
set @pattern2 = @pattern+0xFF
select @pattern,@pattern2
SELECT
*
FROM @t
WHERE val<@pattern
OR val>@pattern2
Run Code Online (Sandbox Code Playgroud)
这是完全失败的,如果我使用 4 个符号作为图案,图案最多可以精确到 2 个符号,只有当图案位于预定义位置时,它才会起作用。我已经尝试过这个和下面所有内容的组合。
WHERE CONVERT(varbinary(2), val) = 0xdata
Run Code Online (Sandbox Code Playgroud)
还有这个:
select *
from table …Run Code Online (Sandbox Code Playgroud) 如果我有一个类型为binary或 的列varbinary,我将数据想象为一个位序列。例如,对我来说,01001(作为基数 2 的数字)可能是列中的有效值是有意义的binary(5)。
为什么以这种方式插入和显示二进制数据并不简单?
例如,为什么 SSMS 将二进制数据转换为十六进制,而不是显示一系列 1 和 0(在我看来,这更容易推理)?
varbinary ×13
sql-server ×10
blob ×2
xml ×2
compression ×1
disk-space ×1
encoding ×1
filestream ×1
index ×1
query ×1
ssms ×1
statistics ×1
varchar ×1