## 背景
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實例:
?
將這個結果集放在一個表中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對象:

~~~
{
"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團隊