## 背景
SQL Server是一种强大的数据库引擎,不仅性能卓越,稳定,功能还很强大,SQL Server 2016中已经支持JSON。这让我想到以前工作中经常使用的SQL XML,也对比一下他们几个关键领域的应用方法。这两种SQL特性,在实际的工作中也是常用的功能,特别是JSON在最近发展非常火爆,SQL Server也不落后,很快就在SQL Server2016支持。
## 广义的XML与JSON
XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML使用文档类型定义来组织数据;格式统一,跨平台,它早已成为业界公认的标准。JSON一种轻量级的数据交换格式,具有良好的可读和便于快速编写的特性。可在不同平台之间进行数据交换。JSON采用兼容性很高的、完全独立于语言文本格式。关于他的比较,这篇文介绍得非常全面:[JSON与XML的区别比较](http://www.cnblogs.com/SanMaoSpace/p/3139186.html)
## SQL XML与SQL JSON
使用 xml 数据类型,可以将 XML 文档和片段存储在 SQL Server 数据库中,可以创建 xml 类型的列和变量,并存储 XML 实例。可以选择性地将 XML 架构集合与 xml 数据类型的列、参数或变量进行关联。JSON是一种文本化的数据格式,与xml作为一种数据类型不同,JSON本身在SQL Server中只是一种字符串,用于存储非结构化的数据。根据以前的经验,在SQL Server T-SQL应用中,XML应用主要在下面几个方面:
1\. 路径表达式;
2\. 查询解析;
3\. 生成实例;
4\. 实例更改;
5\. 索引。
而JSON其实也是类似的应用。下面将介绍SQL XML和SQL JSON具体在这几个方面的应用,请注意,下面的示例请在SQL Server 2016 RC3以上版本运行。
## 路径表达式
### SQL XML路径表达式
xml数据类型自己是没有路径表达式,但SQL Server实现了XQuery语言,该语言支持SQL Server xml数据类型的操作。路径表达式是XQuery最重要的表达式之一,XQuery 路径表达式用于定位文档中的节点,如元素节点、属性节点和文本节点。言归正传,您需要理解以下概念:
#### 相对路径表达式
相对路径表达式由一个或多个步骤组成,步骤间以单斜杠或双斜杠(/ 或 //)分隔。例如:
~~~
child::Features 是相对路径表达式,其中 Child 仅指上下文节点的子节点。
~~~
#### 绝对路径表达式
child::Features 是相对路径表达式,其中 Child 仅指上下文节点的子节点。例如:
表达式 /child::ProductDescription 中的起始斜杠表示它是一个绝对路径表达式。 因为表达式开始处的斜杠返回上下文节点的文档根节点。
#### 轴
轴包含六个概念child,parent,attribute,seft,descendant-or-self,descendant,其中parent是逆向的,其余都是正向的。从名字上能够区分它们的用途。你甚至不必去了解其中含义,看看下面的示例就明白:
~~~
DECLARE
@xml_sample xml
SET @xml_sample=
N'<root>
<a e="111" >
<b>
<c>
<d>3333</d>
</c>
</b>
</a>
<f>222</f>
</root>'
SELECT
@xml_sample.query(N'/child::root/child::a') AS child ,
@xml_sample.query(N'/child::root/child::a/descendant::*') AS descendant,
@xml_sample.query(N'/child::root/child::a/self::*') AS _self_ ,
@xml_sample.query(N'/child::root/child::a/parent::root/child::f') AS parent ,
@xml_sample.query(N'/child::root/child::a/descendant-or-self::*') AS des_or_self ,
@xml_sample.value(N'(/child::root/child::a/attribute::e)[1]',N'int') AS attribute
~~~
上面使用了xml数据类型的操作方法query和value,应用路径表达式的轴节步骤得到不同结果,对比一下结果,就很清晰了。其中*表示以一个节点测试表示节点名称。
#### 节点测试
节点测试是一个条件,并且是路径表达式中的轴步骤的第二个组件。 在步骤中选定的所有节点都必须满足此条件,他有两种节点测试条件:
* 节点名
节点名包括属性节点名称和元素节点名称。
* 节点类型
节点类型包括comment(),node(),text(),processing-instruction() ,具体含义你也不必深入下去,有兴趣的可自查。
下面用一个示例来说明节点名和节点类型:
~~~
DECLARE
@xml_sample xml
SET @xml_sample=
N'<root>
<a e="111" >
<!-- my comment -->
<b>
<c>
<d>3333</d>
</c>
</b>
</a>
<f>222</f>
</root>'
SELECT
@xml_sample.query(N'/child::root/child::a') AS element_node ,
@xml_sample.value(N'(/child::root/child::a/attribute::e)[1]',N'int') AS attribute_node ,
@xml_sample.value(N'(/child::root/child::f/child::text())[1]',N'int') AS text_type ,
@xml_sample.query(N'/child::root/child::a/child::node()') AS node_type ,
@xml_sample.query(N'/child::root/child::a/child::comment()') AS comment_type
~~~
在实际应用中,节点测试用得最多的是节点名和text()类型,需要指出的是在处理大量的xml实例时,如果解析节点文本,不添加text()节点测试,性能会有所影响,可简单自测性能。
可能你会在写路径表达式的时候会感觉到很繁琐,那么,上面两个实例换种方式,就清晰了:
~~~
DECLARE
@xml_sample xml
SET @xml_sample=
N'<root>
<a e="111" >
<!-- my comment -->
<b>
<c>
<d>3333</d>
</c>
</b>
</a>
<f>222</f>
</root>'
SELECT
@xml_sample.query(N'/root/a') AS element_node ,
@xml_sample.value(N'(/root/a/@e)[1]',N'int') AS attribute_node ,
@xml_sample.value(N'(/root/f/text())[1]',N'int') AS text_type ,
@xml_sample.query(N'/root/a/node()') AS node_type ,
@xml_sample.query(N'/root/a/comment()') AS comment_type
SELECT
@xml_sample.query(N'/root/a') AS child ,
@xml_sample.query(N'/root/a/descendant::*') AS descendant,
@xml_sample.query(N'/root/a/self::*') AS _self_ ,
@xml_sample.query(N'/root/a/../f') AS parent ,
@xml_sample.query(N'/root/a/descendant-or-self::*') AS des_or_self ,
@xml_sample.value(N'(/root/a/@e)[1]',N'int') AS attribute
~~~
child被省略掉了,这是默认行为,你也不必写parent节点,直接用两点代替”..”,属性用@表示
#### 谓词
谓词通过应用指定的测试来筛选节点序列。 谓词表达式用方括号括起来并绑定到路径表达式中的最后一个节点。有点类似我们基础SQL中的谓词逻辑,比如WHERE条件,你可简单理解为一种条件关系,看下面的示例:
~~~
DECLARE
@xml_sample xml ,
@i int =2
SET @xml_sample = N'
<root>
<a>
<b>b1</b>
<c>111</c>
</a>
<a>
<b>b2</b>
<c>222</c>
</a>
</root>
'
SELECT
@xml_sample.query(N'/root/a[2]'),
@xml_sample.query(N'(/root/a/b)[1]'),
@xml_sample.query(N'/root/a/b[text()="b2"]'),
@xml_sample.query(N'/root/a[sql:variable("@i")]')
~~~
轴、节点测试和谓词是轴步骤的要素,还有一般步骤,这个很少用,有兴趣可以自行了解。
## SQL JSON路径表达式
JSON中的路径表达式非常简单,你只需要理解下列两个核心概念就可以随心应手:
#### 路径模式
JSON的路径模式有两种,一种是lax,另外一种是strict,默认的方式是lax。lax模式在路径表达式遇到错误时返回为空,而strict模式会抛出错误,请运行下列语句:
~~~
DECLARE
@json_sample varchar(500)=
N'{
"info":{
"type":1,
"address":{
"town":"Bristol",
"county":"Avon",
"country":"England"
},
"tags":["Sport", "Water polo"]
},
"type":"Basic"
}'
SELECT
JSON_VALUE(@json_sample,'$.type')
SELECT
JSON_QUERY(@json_sample,'$.type')
SELECT
JSON_QUERY(@json_sample,'lax $.type')
SELECT
JSON_QUERY(@json_sample,'strict $.type')
~~~
#### 路径
JSON数据的上下文引用使用美元符号$表示,JSON中的各属性作为路径关键名称,比如 $.type,如果属性名称有空格,需要用双引号括起来。如果是数组,需要使用方括号表示位置。“.”表示对象的一个成员。例如:
~~~
DECLARE
@json_sample varchar(500)=
N'{"people":
[
{ "name": "John", "surname": "Doe" },
{ "name": "Jane", "surname": null, "active": true }
]
} '
SELECT
JSON_VALUE(@json_sample,'$.people[0].name') ,
JSON_VALUE(@json_sample,'$.people[1].active'),
JSON_QUERY(@json_sample,'$.people[1]'),
JSON_QUERY(@json_sample,'$')
~~~
## 查询解析
现在我准备了两个实例,一个是xml,一个是JSON,他们表达的内容是一样的,以这个实例来对比一下查询解析功能。
xml :
~~~
<ROOT>
<Customers CustomerID="VINET" ContactName="Paul Henriot">
<Orders>
<EmployeeID>5</EmployeeID>
<OrderDate>1996-07-04</OrderDate>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>11</ProductID>
<Quantity>12</Quantity>
</Order_Details>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>42000</ProductID>
<Quantity>11111</Quantity>
</Order_Details>
</Orders>
</Customers>
<Customers CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Orders>
<EmployeeID>3</EmployeeID>
<OrderDate>1996-07-06</OrderDate>
<Order_Details>
<OrderID>10283</OrderID>
<ProductID>22</ProductID>
<Quantity>3</Quantity>
</Order_Details>
</Orders>
</Customers>
</ROOT>
~~~
JSON :
~~~
{
"ROOT": {
"Customers": [
{
"CustomerID": "VINET",
"ContactName": "Paul Henriot",
"Orders": {
"EmployeeID": "5",
"OrderDate": "1996-07-04",
"Order_Details": [
{
"OrderID": "10248",
"ProductID": "11",
"Quantity": "12"
},
{
"OrderID": "10248",
"ProductID": "42000",
"Quantity": "11111"
}
]
}
},
{
"CustomerID": "LILAS",
"ContactName": "Carlos Gonzlez",
"Orders": {
"EmployeeID": "3",
"OrderDate": "1996-07-06",
"Order_Details": {
"OrderID": "10283",
"ProductID": "22",
"Quantity": "3"
}
}
}
]
}
}
~~~
### SQL XML查询解析
在SQL Server中,解析经常使用这些方法:query(),nodes(),value(),openxml,有时也用到exist方法来判定条件。
#### 得到子实例片段
得到实例片段非常简单,使用query方法就好。例如得到CustomerID=“LILAS”的片段Customers信息:
~~~
DECLARE
@xml_sample xml
SET @xml_sample =N'
<ROOT>
<Customers CustomerID="VINET" ContactName="Paul Henriot">
<Orders>
<EmployeeID>5</EmployeeID>
<OrderDate>1996-07-04</OrderDate>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>11</ProductID>
<Quantity>12</Quantity>
</Order_Details>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>42000</ProductID>
<Quantity>11111</Quantity>
</Order_Details>
</Orders>
</Customers>
<Customers CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Orders>
<EmployeeID>3</EmployeeID>
<OrderDate>1996-07-06</OrderDate>
<Order_Details>
<OrderID>10283</OrderID>
<ProductID>22</ProductID>
<Quantity>3</Quantity>
</Order_Details>
</Orders>
</Customers>
</ROOT>
'
SELECT
@xml_sample.query(N'/ROOT/Customers[@CustomerID="LILAS"]')
~~~
#### 得到元素节点文本
得到元素文本值是最基本的操作,现在要获得 CustomerID=”VINET” 的EmployeeID:
~~~
DECLARE
@xml_sample xml
SET @xml_sample =N'
<ROOT>
<Customers CustomerID="VINET" ContactName="Paul Henriot">
<Orders>
<EmployeeID>5</EmployeeID>
<OrderDate>1996-07-04</OrderDate>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>11</ProductID>
<Quantity>12</Quantity>
</Order_Details>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>42000</ProductID>
<Quantity>11111</Quantity>
</Order_Details>
</Orders>
</Customers>
<Customers CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Orders>
<EmployeeID>3</EmployeeID>
<OrderDate>1996-07-06</OrderDate>
<Order_Details>
<OrderID>10283</OrderID>
<ProductID>22</ProductID>
<Quantity>3</Quantity>
</Order_Details>
</Orders>
</Customers>
</ROOT>
'
SELECT
@xml_sample.value(N'(/ROOT/Customers[@CustomerID="VINET"]/Orders/EmployeeID/text())[1]',N'int')
~~~
#### 得到属性值
属性值在路径表达式说过,可以使用attribute或者@标识。比如要得到ContactName:
~~~
DECLARE
@xml_sample xml
SET @xml_sample =N'
<ROOT>
<Customers CustomerID="VINET" ContactName="Paul Henriot">
<Orders>
<EmployeeID>5</EmployeeID>
<OrderDate>1996-07-04</OrderDate>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>11</ProductID>
<Quantity>12</Quantity>
</Order_Details>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>42000</ProductID>
<Quantity>11111</Quantity>
</Order_Details>
</Orders>
</Customers>
<Customers CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Orders>
<EmployeeID>3</EmployeeID>
<OrderDate>1996-07-06</OrderDate>
<Order_Details>
<OrderID>10283</OrderID>
<ProductID>22</ProductID>
<Quantity>3</Quantity>
</Order_Details>
</Orders>
</Customers>
</ROOT>
'
SELECT
CustomerID=T.c.value(N'@CustomerID',N'varchar(50)'),
ContactName=T.c.value(N'@ContactName',N'varchar(50)')
FROM @xml_sample.nodes(N'ROOT/Customers') T(c)
~~~
#### 构建结果集
现在需要将订单细节和其他信息都生成一个结果集,这个可能觉得很麻烦,其实也不难,只要充分理解路径表达式,看看可以怎么做到?有两种方法:
第一种:nodes()方法
~~~
DECLARE
@xml_sample xml
SET @xml_sample =N'
<ROOT>
<Customers CustomerID="VINET" ContactName="Paul Henriot">
<Orders>
<EmployeeID>5</EmployeeID>
<OrderDate>1996-07-04</OrderDate>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>11</ProductID>
<Quantity>12</Quantity>
</Order_Details>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>42000</ProductID>
<Quantity>11111</Quantity>
</Order_Details>
</Orders>
</Customers>
<Customers CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Orders>
<EmployeeID>3</EmployeeID>
<OrderDate>1996-07-06</OrderDate>
<Order_Details>
<OrderID>10283</OrderID>
<ProductID>22</ProductID>
<Quantity>3</Quantity>
</Order_Details>
</Orders>
</Customers>
</ROOT>
'
SELECT
CustomerID=T.c.value(N'../../@CustomerID',N'varchar(50)'),
ContactName=T.c.value(N'../../@ContactName',N'varchar(50)'),
EmployeeID=T.c.value(N'(../EmployeeID/text())[1]',N'int'),
OrderDate=T.c.value(N'(../OrderDate/text())[1]',N'datetime'),
OrderID=T.c.value(N'(OrderID/text())[1]',N'int'),
ProductID=T.c.value(N'(ProductID/text())[1]',N'int'),
Quantity=T.c.value(N'(Quantity/text())[1]',N'int')
FROM @xml_sample.nodes(N'ROOT/Customers/Orders/Order_Details') T(c)
~~~
第二种:openxml 方法
~~~
DECLARE
@idoc int,
@doc varchar(4000)
SET @doc=N'
<ROOT>
<Customers CustomerID="VINET" ContactName="Paul Henriot">
<Orders>
<EmployeeID>5</EmployeeID>
<OrderDate>1996-07-04</OrderDate>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>11</ProductID>
<Quantity>12</Quantity>
</Order_Details>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>42000</ProductID>
<Quantity>11111</Quantity>
</Order_Details>
</Orders>
</Customers>
<Customers CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Orders>
<EmployeeID>3</EmployeeID>
<OrderDate>1996-07-06</OrderDate>
<Order_Details>
<OrderID>10283</OrderID>
<ProductID>22</ProductID>
<Quantity>3</Quantity>
</Order_Details>
</Orders>
</Customers>
</ROOT>
'
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc;
SELECT
*
FROM OPENXML (@idoc, '/ROOT/Customers/Orders/Order_Details')
WITH (
CustomerID varchar(50) '../../@CustomerID',
ContactName varchar(50) '../../@ContactName',
EmployeeID int '(../EmployeeID/text())[1]',
OrderDate datetime '(../OrderDate/text())[1]',
OrderID int '(OrderID/text())[1]',
ProductID int '(ProductID/text())[1]',
Quantity int '(Quantity/text())[1]'
)
EXEC sp_xml_removedocument @idoc;
~~~
如果你对XQuery感兴趣,你还可以从过这种方式来处理,不过这种方式会比较复杂一点,SQL Server是支持XQuery语言操作,请读者自行尝试。
#### 表列处理
假如你的XML片段存在表中,如果要解析处理,只需要使用CROSS APPLY生成一个多列的结果,用nodes方法就可以了,如果遇到条件,并且与列结合,你可能会用到exist方法和sql:column()来处理,上面的结果已经较复杂,这里不需要演示了。有兴趣可自己实战一下。
### SQL JSON查询解析
JSON解析相对XML要简单得多,没有属性值,没有文本之类。会使用到的方法有:JSON_QUERY(),JSON_VALUE,ISJSON(),OPENJSON() 。
#### 得到JSON片段
得到实例片段,使用JSON_QUERY方法。例如CustomerID=“LILAS”的片段Customers信息,这里没有xml那么强大,可以通过谓词来过滤,至少现在没有看到这个功能。因此只能指定简单的数组值。
~~~
DECLARE
@json_sample varchar(5000)
SET @json_sample=N'{
"ROOT": {
"Customers": [
{
"CustomerID": "VINET",
"ContactName": "Paul Henriot",
"Orders": {
"EmployeeID": "5",
"OrderDate": "1996-07-04",
"Order_Details": [
{
"OrderID": "10248",
"ProductID": "11",
"Quantity": "12"
},
{
"OrderID": "10248",
"ProductID": "42000",
"Quantity": "11111"
}
]
}
},
{
"CustomerID": "LILAS",
"ContactName": "Carlos Gonzlez",
"Orders": {
"EmployeeID": "3",
"OrderDate": "1996-07-06",
"Order_Details": {
"OrderID": "10283",
"ProductID": "22",
"Quantity": "3"
}
}
}
]
}
}
'
SELECT
JSON_QUERY(@json_sample,N'$.ROOT.Customers[1]')
~~~
#### 得到节点值
得到JSON的某个值,使用JSON_VALUE方法就好:
~~~
DECLARE
@json_sample varchar(5000)
SET @json_sample=N'{
"ROOT": {
"Customers": [
{
"CustomerID": "VINET",
"ContactName": "Paul Henriot",
"Orders": {
"EmployeeID": "5",
"OrderDate": "1996-07-04",
"Order_Details": [
{
"OrderID": "10248",
"ProductID": "11",
"Quantity": "12"
},
{
"OrderID": "10248",
"ProductID": "42000",
"Quantity": "11111"
}
]
}
},
{
"CustomerID": "LILAS",
"ContactName": "Carlos Gonzlez",
"Orders": {
"EmployeeID": "3",
"OrderDate": "1996-07-06",
"Order_Details": {
"OrderID": "10283",
"ProductID": "22",
"Quantity": "3"
}
}
}
]
}
}
'
SELECT
JSON_VALUE(@json_sample,N'$.ROOT.Customers[1].Orders.EmployeeID')
~~~
#### 得到结果集
得到结果集,JSON只提供一种方法OPENJSON,没有丰富的路径表达式,因此解析会比较麻烦,下面示例演示与xml生成一样的结果集:
~~~
DECLARE
@json_sample varchar(5000)
SET @json_sample=N'{
"ROOT": {
"Customers": [
{
"CustomerID": "VINET",
"ContactName": "Paul Henriot",
"Orders": {
"EmployeeID": "5",
"OrderDate": "1996-07-04",
"Order_Details": [
{
"OrderID": "10248",
"ProductID": "11",
"Quantity": "12"
},
{
"OrderID": "10248",
"ProductID": "42000",
"Quantity": "11111"
}
]
}
},
{
"CustomerID": "LILAS",
"ContactName": "Carlos Gonzlez",
"Orders": {
"EmployeeID": "3",
"OrderDate": "1996-07-06",
"Order_Details": {
"OrderID": "10283",
"ProductID": "22",
"Quantity": "3"
}
}
}
]
}
}
'
;WITH CustomersJ
AS
(
SELECT
T.*
FROM OPENJSON(@json_sample,N'$.ROOT.Customers')
WITH (
CustomerID varchar(50) N'$.CustomerID' ,
ContactName varchar(50) N'$.ContactName',
EmployeeID int N'$.Orders.EmployeeID',
OrderDate datetime N'$.Orders.OrderDate',
Orders nvarchar(max) AS JSON
) T
)
SELECT
CJ.CustomerID,CJ.ContactName,CJ.EmployeeID,
CJ.OrderDate,O.*
FROM CustomersJ CJ
CROSS APPLY OPENJSON(CJ.Orders,N'$.Order_Details')
WITH (
OrderID int N'$.OrderID' ,
ProductID int N'$.ProductID',
Quantity int N'$.Quantity'
)
~~~
#### 表列处理
表列如果存放的是JSON格式数据,你只需要注意所有列数据需要用CROSS JOIN得到所要处理的JSON对象,其他的也没有特别的。有兴趣可以自己去测试。
## 生成实例
### SQL XML实例生成
生成xml有多种方式,常见的有:常量直接赋值,FOR XML子句,大容量加载:
#### 常量直接赋值
声明一个xml数据类型变量,直接给赋值,这个是最常见的:
例如:
~~~
DECLARE
@xml_sample xml
SET @xml_sample=N'<a><b>111</b></a>'
~~~
如何验证这是一个可用的xml,很简单,执行一下这个语句,变量是xml,如果你的赋值不是xml, 检查是通不过去的,这个有自检查机制保证,如果不是合规的,就会抛错:
~~~
Msg 9436, Level 16, State 1, Line 6
XML parsing: line 1, character 16, end tag does not match start tag
~~~
#### FOR XML子句
FOR XML子句可以将表内数据直接生成XML实例,FOR XML子句有四种方式:FOR XML AUTO,FOR XML PATH,FOR XMLEXPLICIT,FOR XML RAW。
* RAW 模式
将为 SELECT 语句所返回行集中的每行生成一个 元素。
* AUTO 模式
将基于指定 SELECT 语句的方式来使用试探性方法在 XML 结果中生成嵌套。 您对生成的 XML 的形状具有最低限度的控制能力。 除了 AUTO 模式的试探性方法生成的 XML 形状之外,还可以编写 FOR XML 查询来生成 XML 层次结构。
* EXPLICIT 模式
允许对 XML 的形状进行更多控制。 您可以随意混合属性和元素来确定 XML 的形状。 由于执行查询而生成的结果行集需要具有特定的格式。 此行集格式随后将映射为 XML 形状。 使用 EXPLICIT 模式能够随意混合属性和元素、创建包装和嵌套的复杂属性、创建用空格分隔的值(例如 OrderID 属性可能具有一列排序顺序 ID 值)以及混合内容。
* PATH 模式
与嵌套 FOR XML 查询功能一起以较简单的方式提供了 EXPLICIT 模式的灵活性。
实际上,用的最多的是auto和path模式,就我个人习惯,一直用path模式。下面一个示例,看看如何构建一个复杂的xml,请注意构造时属性,元素以及文本的方法:
将下列列表(其实是上面的示例结果)生成一个xml实例:
![](https://box.kancloud.cn/2016-07-22_5791a6c75c72f.jpg)
将这个结果集放在一个表中tb_xml_sample。然后需构造为:
~~~
<ROOT>
<Customers CustomerID="VINET" ContactName="Paul Henriot">
<Orders>
<EmployeeID>5</EmployeeID>
<OrderDate>1996-07-04</OrderDate>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>11</ProductID>
<Quantity>12</Quantity>
</Order_Details>
<Order_Details>
<OrderID>10248</OrderID>
<ProductID>42000</ProductID>
<Quantity>11111</Quantity>
</Order_Details>
</Orders>
</Customers>
<Customers CustomerID="LILAS" ContactName="Carlos Gonzlez">
<Orders>
<EmployeeID>3</EmployeeID>
<OrderDate>1996-07-06</OrderDate>
<Order_Details>
<OrderID>10283</OrderID>
<ProductID>22</ProductID>
<Quantity>3</Quantity>
</Order_Details>
</Orders>
</Customers>
</ROOT>
~~~
下面实现:
~~~
SELECT
CustomerID N'@CustomerID',
ContactName N'@ContactName',
EmployeeID N'Orders/EmployeeID',
OrderDate N'Orders/OrderDate',
Orders= (
SELECT
OrderID ,ProductID,Quantity
FROM tb_xml_sample I1
WHERE I1.EmployeeID=O1.EmployeeID
AND I1.OrderDate=O1.OrderDate
FOR XML PATH(N'Order_Details'),TYPE
)
FROM tb_xml_sample O1
GROUP BY CustomerID,ContactName,EmployeeID,OrderDate
ORDER BY 1 DESC
FOR XML PATH(N'Customers'),ROOT(N'ROOT')
~~~
关于PATH(N’’),ROOT(N’’),TYPE等指令,请G一下就明白,主要是生成层次结构及XML正确性验证。
#### 大容量加载
如果xml是一个文件,也可以通过OPENROWSET将文件读取到SQL Server中,如果事先不知道 XML 文档的编码方式,并且数据在转换到 XML 之前被作为字符串或二进制数据而不是 XML 数据来传递,则建议将数据作为 varbinary 处理。
例如,上面的XML保存到文件,然后在SQL Server中读出来:
~~~
SELECT
xml_sample=CAST(CAST(T.c AS varbinary(max)) AS XML) ,
T.c
FROM OPENROWSET(BULK 'C:\xml_sample.xml', SINGLE_BLOB) T(c)
~~~
## SQL JSON实例生成
与XML一样,生成JSON有多种方式,但常见的有常量直接赋值,FOR JSON子句,大容量加载。
#### 常量直接赋值
这个最常用,也是最简单,但JSON在SQL Server是没有类型存在的,要验证JSON是否是合规的,使用ISJOIN判断,ISJOIN为1表示是合规的,为0表示不合规:
~~~
DECLARE
@json_sample nvarchar(500)
SET @json_sample=N'{
"Order":{
"OrderID":1222 ,
"OrderDate": "2016-07-08 00:00:000" ,
"OrderSalary": 1000
}
}
'
SELECT ISJSON(@json_sample)
SET @json_sample=N'
"Order":{
"OrderID":1222 ,
"OrderDate": "2016-07-08 00:00:000" ,
"OrderSalary": 1000
}
'
SELECT ISJSON(@json_sample)
~~~
#### FOR JSON子句
FOR JSON 有两种模式,一种是FOR JSON AUTO,另一种是FOR JSON PATH,FOR JSON有几个重要的参数:ROOT(JSON数据的根节点),INCLUDE_NULL_VALUES (处理空间节点时如何显示),WITHOUT_ARRAY_WRAPPER(是否使用方括号将对象包起来)。
* FOR JSON AUTO模式
FOR JSON子句在使用PATH模式时,可以控制JSON格式的输出,可以创建复杂的JSON对象。
* FOR JSON PATH模式
FOR JSON子句在使用AUTO模式时,JSON输出的格式是查询语句自动完成,因此不能灵活控制JSON的格式。
同样地,我们以查询分析语句那示例来构造JSON对象:
![](https://box.kancloud.cn/2016-07-22_5791a6c75c72f.jpg)
~~~
{
"ROOT": {
"Customers": [
{
"CustomerID": "VINET",
"ContactName": "Paul Henriot",
"Orders": {
"EmployeeID": "5",
"OrderDate": "1996-07-04",
"Order_Details": [
{
"OrderID": "10248",
"ProductID": "11",
"Quantity": "12"
},
{
"OrderID": "10248",
"ProductID": "42000",
"Quantity": "11111"
}
]
}
},
{
"CustomerID": "LILAS",
"ContactName": "Carlos Gonzlez",
"Orders": {
"EmployeeID": "3",
"OrderDate": "1996-07-06",
"Order_Details": {
"OrderID": "10283",
"ProductID": "22",
"Quantity": "3"
}
}
}
]
}
}
~~~
JSON对象生成,依然用这个表tb_xml_sample:
~~~
SELECT
DISTINCT
CustomerID N'CustomerID' ,
ContactName N'ContactName',
EmployeeID N'Orders.EmployeeID',
OrderDate N'Orders.OrderDate',
Orders=
( SELECT
OrderID N'OrderID',
ProductID N'ProductID',
Quantity N'Quantity'
FROM tb_xml_sample I
WHERE I.EmployeeID=O.EmployeeID
AND I.OrderDate=O.OrderDate
FOR JSON PATH,ROOT(N'Order_Details')
)
FROM tb_xml_sample O
ORDER BY 1 DESC
FOR JSON PATH,ROOT(N'ROOT')
这段其实运行是有错误的,Property 'Orders' cannot be generated in JSON output due to a conflict with another column name or alias。而实际上,根据XML来看,这个地方出错是不应该的,我需要将EmployeeID/OrderDate 放在Orders下面是很正常的需求。目前的SQL JSON确实做不到(SQL Server 2016 RC3)。那么只有将EmployeeID/OrderDate与ContactName/CustomerID 同一层次位置 ,要完全构造成与上面的一样,目前看来存在问题,这个地方需要继续跟进下去,或许有更多的办法或产品更新 。
SELECT
DISTINCT
CustomerID N'CustomerID' ,
ContactName N'ContactName',
EmployeeID N'EmployeeID',
OrderDate N'OrderDate',
Orders=
( SELECT
OrderID N'OrderID',
ProductID N'ProductID',
Quantity N'Quantity'
FROM tb_xml_sample I
WHERE I.EmployeeID=O.EmployeeID
AND I.OrderDate=O.OrderDate
FOR JSON PATH,ROOT(N'Order_Details')
)
FROM tb_xml_sample O
ORDER BY 1 DESC
FOR JSON PATH,ROOT(N'ROOT')
~~~
#### 大容量加载
大容量加载也是通过OPENROWSET ,与XML一样:
~~~
SELECT
xml_sample=CAST(CAST(T.c AS varbinary(max)) AS varchar(max)) ,
T.c
FROM OPENROWSET(BULK 'C:\json_sample.json', SINGLE_BLOB) T(c)
~~~
## 实例更改
### SQL XML更改实例
实例修改在实际应用中会很少,这里的修改包括DML_XML,使用modify方法,包括删除,更新和插入。下列一个示例表示所有信息:
* 插入 insert
可以插入xml片段,可以插入属性,文本,注释,指令,CDATA部分数据,请看下面示例:
~~~
DECLARE
@xml_sample xml
SET @xml_sample=N'
<root>
<name>yang</name>
<sex>man</sex>
<other></other>
<hobby>
<item>football</item>
<item>playgames</item>
</hobby>
</root>
--insert as first
SET @xml_sample.modify(N'
insert <firstname>ay15</firstname>
as first
into (/root)[1]
')
SELECT @xml_sample
--insret as last
SET @xml_sample.modify(N'
insert <lastname>l.p</lastname>
as last
into (/root)[1]
')
SELECT @xml_sample
--insert attribute
SET @xml_sample.modify(N'
insert
(
attribute age {"50"},
attribute nation {"china"}
)
into (/root)[1]
')
SELECT @xml_sample
--insert text value: as first
SET @xml_sample.modify(N'
insert
text{"this text |"}
as first
into (/root/sex)[1]
')
SELECT @xml_sample
--insert text value: as last
SET @xml_sample.modify(N'
insert
text{"|||this text "}
as last
into (/root/sex)[1]
')
SELECT @xml_sample
~~~
* 删除 delete
删除 XML 实例的节点。这个非常的简单:
~~~
DECLARE
@xml_sample xml
SET @xml_sample=N'
<root>
<name>yang</name>
<sex>man</sex>
<other></other>
<hobby>
<item>football</item>
<item>playgames</item>
</hobby>
</root>
'
--insert as first
SET @xml_sample.modify(N'
delete (/root/hobby/item)[2]
')
SELECT @xml_sample
~~~
* 替代 replace value of 在文档中更新节点的值。
~~~
DECLARE
@xml_sample xml
SET @xml_sample=N'
<root age="50">
<name>yang</name>
<sex>man</sex>
<other></other>
<hobby>
<item>football</item>
<item>playgames</item>
</hobby>
</root>
'
--update text value
SET @xml_sample.modify(N'
replace value of (/root/name/text())[1]
with "zhao"
')
SELECT @xml_sample
--update attribute value
--update text value
SET @xml_sample.modify(N'
replace value of (/root/@age)[1]
with "10"
')
SELECT @xml_sample
~~~
### SQL JSON更改实例
JSON的对象修改使用JSON_MODIFY方法,同样具有更新,插入,删除等操作,里面列举一示例:
语法:JSON_MODIFY ( expression , path , newValue ),特别留意path中可以指定lax,strict这个上面已经说过。另外还append关键字,表示追加一个新的值到数组中。
~~~
DECLARE
@json_sample varchar(500)
SET @json_sample='{
"name":"yang",
"sex": "man",
"hobby":[
"football",
"playgames"
]
}'
SELECT
JSON_MODIFY(@json_sample,'$.name','zhao') , --update
JSON_MODIFY(@json_sample,'$.lastname','ay15') , --insert
JSON_MODIFY(@json_sample,'$.sex',null), --delete
JSON_MODIFY(@json_sample,'append $.hobby','running') --add array element
SELECT
JSON_MODIFY(
JSON_MODIFY(
JSON_MODIFY(
JSON_MODIFY(@json_sample
,'$.name','zhao'),
'$.lastname','ay15') ,
'$.sex',null),
'append $.hobby','running')
~~~
## 索引
### SQL XML的索引
这里不介绍,请参考:[Indexes on XML Data Type Columns](https://technet.microsoft.com/en-us/library/ms191497(v=sql.105).aspx)
### SQL JSON的索引
这里不介绍,请参考:[Index JSON data](https://msdn.microsoft.com/en-us/library/mt612798.aspx)
## 总结
上面是SQL Server在XML和JSON方面的简单应用,也是日常工作中经常遇到了,你不必要去了解复杂的xml,XQuery,也不必理解那些深奥难懂大概念,用最简单的实例,处理工作总最需要的知识。希望对大家有用。
- 数据库内核月报目录
- 数据库内核月报 - 2016/09
- MySQL · 社区贡献 · AliSQL那些事儿
- PetaData · 架构体系 · PetaData第二代低成本存储体系
- MySQL · 社区动态 · MariaDB 10.2 前瞻
- MySQL · 特性分析 · 执行计划缓存设计与实现
- PgSQL · 最佳实践 · pg_rman源码浅析与使用
- MySQL · 捉虫状态 · bug分析两例
- PgSQL · 源码分析 · PG优化器浅析
- MongoDB · 特性分析· Sharding原理与应用
- PgSQL · 源码分析 · PG中的无锁算法和原子操作应用一则
- SQLServer · 最佳实践 · TEMPDB的设计
- 数据库内核月报 - 2016/08
- MySQL · 特性分析 ·MySQL 5.7新特性系列四
- PgSQL · PostgreSQL 逻辑流复制技术的秘密
- MySQL · 特性分析 · MyRocks简介
- GPDB · 特性分析· Greenplum 备份架构
- SQLServer · 最佳实践 · RDS for SQLServer 2012权限限制提升与改善
- TokuDB · 引擎特性 · REPLACE 语句优化
- MySQL · 专家投稿 · InnoDB物理行中null值的存储的推断与验证
- PgSQL · 实战经验 · 旋转门压缩算法在PostgreSQL中的实现
- MySQL · 源码分析 · Query Cache并发处理
- PgSQL · 源码分析· pg_dump分析
- 数据库内核月报 - 2016/07
- MySQL · 特性分析 ·MySQL 5.7新特性系列三
- MySQL · 特性分析 · 5.7 代价模型浅析
- PgSQL · 实战经验 · 分组TOP性能提升44倍
- MySQL · 源码分析 · 网络通信模块浅析
- MongoDB · 特性分析 · 索引原理
- SQLServer · 特性分析 · XML与JSON应用比较
- MySQL · 最佳实战 · 审计日志实用案例分析
- MySQL · 性能优化 · 条件下推到物化表
- MySQL · 源码分析 · Query Cache内部剖析
- MySQL · 捉虫动态 · 备库1206错误问题说明
- 数据库内核月报 - 2016/06
- MySQL · 特性分析 · innodb 锁分裂继承与迁移
- MySQL · 特性分析 ·MySQL 5.7新特性系列二
- PgSQL · 实战经验 · 如何预测Freeze IO风暴
- GPDB · 特性分析· Filespace和Tablespace
- MariaDB · 新特性 · 窗口函数
- MySQL · TokuDB · checkpoint过程
- MySQL · 特性分析 · 内部临时表
- MySQL · 最佳实践 · 空间优化
- SQLServer · 最佳实践 · 数据库实现大容量插入的几种方式
- 数据库内核月报 - 2016/05
- MySQL · 引擎特性 · 基于InnoDB的物理复制实现
- MySQL · 特性分析 · MySQL 5.7新特性系列一
- PostgreSQL · 特性分析 · 逻辑结构和权限体系
- MySQL · 特性分析 · innodb buffer pool相关特性
- PG&GP · 特性分析 · 外部数据导入接口实现分析
- SQLServer · 最佳实践 · 透明数据加密在SQLServer的应用
- MySQL · TokuDB · 日志子系统和崩溃恢复过程
- MongoDB · 特性分析 · Sharded cluster架构原理
- PostgreSQL · 特性分析 · 统计信息计算方法
- MySQL · 捉虫动态 · left-join多表导致crash
- 数据库内核月报 - 2016/04
- MySQL · 参数故事 · innodb_additional_mem_pool_size
- GPDB · 特性分析 · Segment事务一致性与异常处理
- GPDB · 特性分析 · Segment 修复指南
- MySQL · 捉虫动态 · 并行复制外键约束问题二
- PgSQL · 性能优化 · 如何潇洒的处理每天上百TB的数据增量
- Memcached · 最佳实践 · 热点 Key 问题解决方案
- MongoDB · 最佳实践 · 短连接Auth性能优化
- MySQL · 最佳实践 · RDS 只读实例延迟分析
- MySQL · TokuDB · TokuDB索引结构--Fractal Tree
- MySQL · TokuDB · Savepoint漫谈
- 数据库内核月报 - 2016/03
- MySQL · TokuDB · 事务子系统和 MVCC 实现
- MongoDB · 特性分析 · MMAPv1 存储引擎原理
- PgSQL · 源码分析 · 优化器逻辑推理
- SQLServer · BUG分析 · Agent 链接泄露分析
- Redis · 特性分析 · AOF Rewrite 分析
- MySQL · BUG分析 · Rename table 死锁分析
- MySQL · 物理备份 · Percona XtraBackup 备份原理
- GPDB · 特性分析· GreenPlum FTS 机制
- MySQL · 答疑解惑 · 备库Seconds_Behind_Master计算
- MySQL · 答疑解惑 · MySQL 锁问题最佳实践
- 数据库内核月报 - 2016/02
- MySQL · 引擎特性 · InnoDB 文件系统之文件物理结构
- MySQL · 引擎特性 · InnoDB 文件系统之IO系统和内存管理
- MySQL · 特性分析 · InnoDB transaction history
- PgSQL · 会议见闻 · PgConf.Russia 2016 大会总结
- PgSQL · 答疑解惑 · PostgreSQL 9.6 并行查询实现分析
- MySQL · TokuDB · TokuDB之黑科技工具
- PgSQL · 性能优化 · PostgreSQL TPC-C极限优化玩法
- MariaDB · 版本特性 · MariaDB 的 GTID 介绍
- MySQL · 特性分析 · 线程池
- MySQL · 答疑解惑 · mysqldump tips 两则
- 数据库内核月报 - 2016/01
- MySQL · 引擎特性 · InnoDB 事务锁系统简介
- GPDB · 特性分析· GreenPlum Primary/Mirror 同步机制
- MySQL · 专家投稿 · MySQL5.7 的 JSON 实现
- MySQL · 特性分析 · 优化器 MRR & BKA
- MySQL · 答疑解惑 · 物理备份死锁分析
- MySQL · TokuDB · Cachetable 的工作线程和线程池
- MySQL · 特性分析 · drop table的优化
- MySQL · 答疑解惑 · GTID不一致分析
- PgSQL · 特性分析 · Plan Hint
- MariaDB · 社区动态 · MariaDB on Power8 (下)
- 数据库内核月报 - 2015/12
- MySQL · 引擎特性 · InnoDB 事务子系统介绍
- PgSQL · 特性介绍 · 全文搜索介绍
- MongoDB · 捉虫动态 · Kill Hang问题排查记录
- MySQL · 参数优化 ·RDS MySQL参数调优最佳实践
- PgSQL · 特性分析 · 备库激活过程分析
- MySQL · TokuDB · 让Hot Backup更完美
- PgSQL · 答疑解惑 · 表膨胀
- MySQL · 特性分析 · Index Condition Pushdown (ICP)
- MariaDB · 社区动态 · MariaDB on Power8
- MySQL · 特性分析 · 企业版特性一览
- 数据库内核月报 - 2015/11
- MySQL · 社区见闻 · OOW 2015 总结 MySQL 篇
- MySQL · 特性分析 · Statement Digest
- PgSQL · 答疑解惑 · PostgreSQL 用户组权限管理
- MySQL · 特性分析 · MDL 实现分析
- PgSQL · 特性分析 · full page write 机制
- MySQL · 捉虫动态 · MySQL 外键异常分析
- MySQL · 答疑解惑 · MySQL 优化器 range 的代价计算
- MySQL · 捉虫动态 · ORDER/GROUP BY 导致 mysqld crash
- MySQL · TokuDB · TokuDB 中的行锁
- MySQL · 捉虫动态 · order by limit 造成优化器选择索引错误
- 数据库内核月报 - 2015/10
- MySQL · 引擎特性 · InnoDB 全文索引简介
- MySQL · 特性分析 · 跟踪Metadata lock
- MySQL · 答疑解惑 · 索引过滤性太差引起CPU飙高分析
- PgSQL · 特性分析 · PG主备流复制机制
- MySQL · 捉虫动态 · start slave crash 诊断分析
- MySQL · 捉虫动态 · 删除索引导致表无法打开
- PgSQL · 特性分析 · PostgreSQL Aurora方案与DEMO
- TokuDB · 捉虫动态 · CREATE DATABASE 导致crash问题
- PgSQL · 特性分析 · pg_receivexlog工具解析
- MySQL · 特性分析 · MySQL权限存储与管理
- 数据库内核月报 - 2015/09
- MySQL · 引擎特性 · InnoDB Adaptive hash index介绍
- PgSQL · 特性分析 · clog异步提交一致性、原子操作与fsync
- MySQL · 捉虫动态 · BUG 几例
- PgSQL · 答疑解惑 · 诡异的函数返回值
- MySQL · 捉虫动态 · 建表过程中crash造成重建表失败
- PgSQL · 特性分析 · 谈谈checkpoint的调度
- MySQL · 特性分析 · 5.6 并行复制恢复实现
- MySQL · 备库优化 · relay fetch 备库优化
- MySQL · 特性分析 · 5.6并行复制事件分发机制
- MySQL · TokuDB · 文件目录谈
- 数据库内核月报 - 2015/08
- MySQL · 社区动态 · InnoDB Page Compression
- PgSQL · 答疑解惑 · RDS中的PostgreSQL备库延迟原因分析
- MySQL · 社区动态 · MySQL5.6.26 Release Note解读
- PgSQL · 捉虫动态 · 执行大SQL语句提示无效的内存申请大小
- MySQL · 社区动态 · MariaDB InnoDB表空间碎片整理
- PgSQL · 答疑解惑 · 归档进程cp命令的core文件追查
- MySQL · 答疑解惑 · open file limits
- MySQL · TokuDB · 疯狂的 filenum++
- MySQL · 功能分析 · 5.6 并行复制实现分析
- MySQL · 功能分析 · MySQL表定义缓存
- 数据库内核月报 - 2015/07
- MySQL · 引擎特性 · Innodb change buffer介绍
- MySQL · TokuDB · TokuDB Checkpoint机制
- PgSQL · 特性分析 · 时间线解析
- PgSQL · 功能分析 · PostGIS 在 O2O应用中的优势
- MySQL · 引擎特性 · InnoDB index lock前世今生
- MySQL · 社区动态 · MySQL内存分配支持NUMA
- MySQL · 答疑解惑 · 外键删除bug分析
- MySQL · 引擎特性 · MySQL logical read-ahead
- MySQL · 功能介绍 · binlog拉取速度的控制
- MySQL · 答疑解惑 · 浮点型的显示问题
- 数据库内核月报 - 2015/06
- MySQL · 引擎特性 · InnoDB 崩溃恢复过程
- MySQL · 捉虫动态 · 唯一键约束失效
- MySQL · 捉虫动态 · ALTER IGNORE TABLE导致主备不一致
- MySQL · 答疑解惑 · MySQL Sort 分页
- MySQL · 答疑解惑 · binlog event 中的 error code
- PgSQL · 功能分析 · Listen/Notify 功能
- MySQL · 捉虫动态 · 任性的 normal shutdown
- PgSQL · 追根究底 · WAL日志空间的意外增长
- MySQL · 社区动态 · MariaDB Role 体系
- MySQL · TokuDB · TokuDB数据文件大小计算
- 数据库内核月报 - 2015/05
- MySQL · 引擎特性 · InnoDB redo log漫游
- MySQL · 专家投稿 · MySQL数据库SYS CPU高的可能性分析
- MySQL · 捉虫动态 · 5.6 与 5.5 InnoDB 不兼容导致 crash
- MySQL · 答疑解惑 · InnoDB 预读 VS Oracle 多块读
- PgSQL · 社区动态 · 9.5 新功能BRIN索引
- MySQL · 捉虫动态 · MySQL DDL BUG
- MySQL · 答疑解惑 · set names 都做了什么
- MySQL · 捉虫动态 · 临时表操作导致主备不一致
- TokuDB · 引擎特性 · zstd压缩算法
- MySQL · 答疑解惑 · binlog 位点刷新策略
- 数据库内核月报 - 2015/04
- MySQL · 引擎特性 · InnoDB undo log 漫游
- TokuDB · 产品新闻 · RDS TokuDB小手册
- PgSQL · 社区动态 · 说一说PgSQL 9.4.1中的那些安全补丁
- MySQL · 捉虫动态 · 连接断开导致XA事务丢失
- MySQL · 捉虫动态 · GTID下slave_net_timeout值太小问题
- MySQL · 捉虫动态 · Relay log 中 GTID group 完整性检测
- MySQL · 答疑释惑 · UPDATE交换列单表和多表的区别
- MySQL · 捉虫动态 · 删被引用索引导致crash
- MySQL · 答疑释惑 · GTID下auto_position=0时数据不一致
- 数据库内核月报 - 2015/03
- MySQL · 答疑释惑· 并发Replace into导致的死锁分析
- MySQL · 性能优化· 5.7.6 InnoDB page flush 优化
- MySQL · 捉虫动态· pid file丢失问题分析
- MySQL · 答疑释惑· using filesort VS using temporary
- MySQL · 优化限制· MySQL index_condition_pushdown
- MySQL · 捉虫动态·DROP DATABASE外键约束的GTID BUG
- MySQL · 答疑释惑· lower_case_table_names 使用问题
- PgSQL · 特性分析· Logical Decoding探索
- PgSQL · 特性分析· jsonb类型解析
- TokuDB ·引擎机制· TokuDB线程池
- 数据库内核月报 - 2015/02
- MySQL · 性能优化· InnoDB buffer pool flush策略漫谈
- MySQL · 社区动态· 5.6.23 InnoDB相关Bugfix
- PgSQL · 特性分析· Replication Slot
- PgSQL · 特性分析· pg_prewarm
- MySQL · 答疑释惑· InnoDB丢失自增值
- MySQL · 答疑释惑· 5.5 和 5.6 时间类型兼容问题
- MySQL · 捉虫动态· 变量修改导致binlog错误
- MariaDB · 特性分析· 表/表空间加密
- MariaDB · 特性分析· Per-query variables
- TokuDB · 特性分析· 日志详解
- 数据库内核月报 - 2015/01
- MySQL · 性能优化· Group Commit优化
- MySQL · 新增特性· DDL fast fail
- MySQL · 性能优化· 启用GTID场景的性能问题及优化
- MySQL · 捉虫动态· InnoDB自增列重复值问题
- MySQL · 优化改进· 复制性能改进过程
- MySQL · 谈古论今· key分区算法演变分析
- MySQL · 捉虫动态· mysql client crash一例
- MySQL · 捉虫动态· 设置 gtid_purged 破坏AUTO_POSITION复制协议
- MySQL · 捉虫动态· replicate filter 和 GTID 一起使用的问题
- TokuDB·特性分析· Optimize Table
- 数据库内核月报 - 2014/12
- MySQL· 性能优化·5.7 Innodb事务系统
- MySQL· 踩过的坑·5.6 GTID 和存储引擎那会事
- MySQL· 性能优化·thread pool 原理分析
- MySQL· 性能优化·并行复制外建约束问题
- MySQL· 答疑释惑·binlog event有序性
- MySQL· 答疑释惑·server_id为0的Rotate
- MySQL· 性能优化·Bulk Load for CREATE INDEX
- MySQL· 捉虫动态·Opened tables block read only
- MySQL· 优化改进· GTID启动优化
- TokuDB· Binary Log Group Commit with TokuDB
- 数据库内核月报 - 2014/11
- MySQL· 捉虫动态·OPTIMIZE 不存在的表
- MySQL· 捉虫动态·SIGHUP 导致 binlog 写错
- MySQL· 5.7改进·Recovery改进
- MySQL· 5.7特性·高可用支持
- MySQL· 5.7优化·Metadata Lock子系统的优化
- MySQL· 5.7特性·在线Truncate undo log 表空间
- MySQL· 性能优化·hash_scan 算法的实现解析
- TokuDB· 版本优化· 7.5.0
- TokuDB· 引擎特性· FAST UPDATES
- MariaDB· 性能优化·filesort with small LIMIT optimization
- 数据库内核月报 - 2014/10
- MySQL· 5.7重构·Optimizer Cost Model
- MySQL· 系统限制·text字段数
- MySQL· 捉虫动态·binlog重放失败
- MySQL· 捉虫动态·从库OOM
- MySQL· 捉虫动态·崩溃恢复失败
- MySQL· 功能改进·InnoDB Warmup特性
- MySQL· 文件结构·告别frm文件
- MariaDB· 新鲜特性·ANALYZE statement 语法
- TokuDB· 主备复制·Read Free Replication
- TokuDB· 引擎特性·压缩
- 数据库内核月报 - 2014/09
- MySQL· 捉虫动态·GTID 和 DELAYED
- MySQL· 限制改进·GTID和升级
- MySQL· 捉虫动态·GTID 和 binlog_checksum
- MySQL· 引擎差异·create_time in status
- MySQL· 参数故事·thread_concurrency
- MySQL· 捉虫动态·auto_increment
- MariaDB· 性能优化·Extended Keys
- MariaDB·主备复制·CREATE OR REPLACE
- TokuDB· 参数故事·数据安全和性能
- TokuDB· HA方案·TokuDB热备
- 数据库内核月报 - 2014/08
- MySQL· 参数故事·timed_mutexes
- MySQL· 参数故事·innodb_flush_log_at_trx_commit
- MySQL· 捉虫动态·Count(Distinct) ERROR
- MySQL· 捉虫动态·mysqldump BUFFER OVERFLOW
- MySQL· 捉虫动态·long semaphore waits
- MariaDB·分支特性·支持大于16K的InnoDB Page Size
- MariaDB·分支特性·FusionIO特性支持
- TokuDB· 性能优化·Bulk Fetch
- TokuDB· 数据结构·Fractal-Trees与LSM-Trees对比
- TokuDB·社区八卦·TokuDB团队