在 SSAS 系列 - 實現第一個 Cube 以及角色扮演維度,度量值格式化和計算成員的創建 中主要是通過已存在的維度和事實數據創建了一個多維數據集,並同時解釋了 Role-Playing Dimension 角色扮演維度,計算成員,計算成員格式化等內容。在這篇文章中主要是分析和理解在多維數據集設計過程中的聚合函數,對應不同類別的度量值根據需求的不同在聚合函數的選擇上也會有所不同。
繼續使用在上一篇 SSAS 文章中創建的示例,在 BIWORK_FirstCube 中能看到有兩組度量值維度組和各個不同的度量值。
選中 Reseller Sales Amount 右鍵查看屬性 AggregateFunction 聚合函數選擇的是 SUM 聚合,很好理解就是一個求和的操作。
選中 Reseller Sales Count 右鍵查看屬性,聚合函數選擇的是 Count,這個是在創建多維數據集 Cube 的時候自動創建的。
對比一下事實表 FactResellerSales 的結構和在創建 Reseller Sales 和 Internet Sales 度量值組時可供選擇的度量值。所有的值類型的數據像 UnitPrice, ProductStandardCost, SalesAmount 這三個列在右側創建度量值組 Fact Reseller Sales 都出現了,但是多了一個 Fact Reseller Sales Count ,包括在 Fact Internet Sales 下也多出了一個 Fact Internet Sales Count ,很明顯是對事實表做了計數統計。因此在 Reseller Sales Count 度量值那里默認使用了 Count 聚合函數,而對於其它的度量值默認使用的是 SUM 函數。
先來查看一下 Reseller Sales Amount 和 Reseller Sales Count 的在各個產品分類下的結果是多少。
然后再查詢一下數據倉庫的數據,看看在多維數據集中的聚合函數是如何完成計算的。
SELECT COUNT(DISTINCT SalesOrderNumber) AS SalesOrderCount,
COUNT(*) AS SalesOrderLineCount
FROM FactResellerSales
SELECT DISTINCT
dpc.EnglishProductCategoryName AS 'Category',
SUM(fact.SalesAmount) OVER(PARTITION BY dpc.ProductCategoryKey) AS 'Reseller Sales Amount',
COUNT(*) OVER(PARTITION BY dpc.ProductCategoryKey) AS 'Reseller Sales Count'
FROM FactResellerSales AS fact
LEFT JOIN DimProduct AS dp
ON fact.ProductKey = dp.ProductKey
INNER JOIN DimProductSubcategory AS dps
ON dp.ProductSubcategoryKey = dps.ProductSubcategoryKey
INNER JOIN DimProductCategory AS dpc
ON dps.ProductCategoryKey = dpc.ProductCategoryKey
可以看到在 FactResellerSales 事實表中總共有 3796 個訂單或者叫做交易,3796 中共有 60855 筆子訂單業務。類似於在網店下了一個訂單,這個訂單上可能包含了不止一種購買的產品。 同時也可以看到 Category 下統計的 Reseller Sales Amount 和 Reseller Sales Count 的結果和在 Cube 中查詢的結果是一致的。那么通過這種對比,就知道 SSAS 分析服務在創建多維數據集中是如何將我們的數據進行聚合的。 對於非 Key 類型的數值通常默認以 SUM 方式聚合,並且會額外創建一個度量值並以 COUNT 方式聚合表示事實的條數。
SSAS 中的聚合函數
實際上除了 SUM 和 COUNT 之外還有其它的一些聚合函數,在 SSAS 分析服務中我們可以大致將它們分為以下三類:累加性,半累加性和非累加性。
從這個小例子來理解這些聚合函數 -
累加性 - 累加性度量值主要是指父級層次結構中成員的值等於它所有子級成員值的總和。
- Sum - 父級成員值等於它所有子級成員值的總和,這是 SSAS 分析服務默認的聚合函數。
- Count - 計算事實表中特殊列非空值的函數,或者計算事實表的行數。父級成員也可以由它的所有子級成員值相加求得。
很顯然交易金額是通過 SUM 聚合函數實現,交易筆數是通過 COUNT 聚合函數實現。
半累加性 - 半累加性度量值只是對某些子級得到進行聚合。
- Max - 父級成員值等於其所有子級中的最小值。
- Min - 父級成員值等於其所有子級中的最大值。
- FirstChild - 父級成員的值等於子級成員值的總和,但是如果在時間維度中,父級成員的值等於第一個子成員的值。
- LastChild - 父級成員的值等於子級成員值的總和,但是如果在時間維度中,父級成員的值等於最后一個子成員的值。
- FirstNonEmpty - 父級成員的值等於子級成員值的總和,但是如果在時間維度中,父級成員的值等於第一個非空子成員的值。
- LastNonEmpty - 父級成員的值等於子級成員值的總和,但是如果在時間維度中,父級成員的值等於最后一個非空子成員的值。
- AverageOfChildren - 對多維數據集時間維度中最低粒度級別的所有維度進行求和,然后再求平均值,即得所求值。(非空子成員)
- ByAccount - 當多維數據集包含一個賬戶類型的維度時,需要使用按賬戶聚合函數。度量值的按賬戶聚合函數是維度 Account 成員的一個屬性。
比如在這里最大交易金額是通過 MAX 聚合的,最小交易金額是通過 MIN 聚合的,開始庫存在時間維度上應該找第一個非空成員使用到了 FirstNonEmpty 聚合函數,而最后庫存在時間維度上應該找最后一個非空成員的值。因為庫存在實際業務中是不會進行累加操作的,每天開始的庫存和每天結束的庫存也是不一樣的。
非累加性 - 父級成員的值不能由自己的值得到。
- DistinctCount - 非重復計算,對事實表中無重復的列進行計數,成員值是通過對該成員的無重復技術而確定的。
- NONE - 不進行任何聚合。
如果在訂單上進行 DistinctCount,那么訂單就是4筆,因為 D001 算一筆訂單,在這筆訂單里有兩條訂單明細信息。
那么有了這些基礎知識之后,我們可以添加或者修改多維數據集中的度量值並提供合適的聚合函數了。
接着上面的項目,在多維數據集設計中選擇 Reseller Sales 右鍵添加新的度量值。
創建一個度量值 Maximum Sales Amount -
非空訂單總數量 - Product Key Count
在 Usage 中有 Count of non-empty values (非空值計數) 和 Count of rows (行計數),它們的區別是行計數應用到事實表各行,而非空值技術應用到事實表各列。
Sales Order Number Distinct Count 非重復的訂單號
注意在使用非重復計數 Distinct Count 聚合函數的時候,SSAS 會創建一個單獨的度量值組。這是因為 SSAS 分析服務處理非重復計數度量值組時,從事實表中選擇數據的 SQL 查詢會按照非重復計數列來進行排序,以便為非重復計數度量值而進行度量值組的物理數據存儲實現優化。 因此,每一個非重復技術度量值都應該被放在單獨的度量值組中。
保存並部署處理多維數據集,在 Excel 中瀏覽這些數據。(Reseller Sales Count 是 SSAS 自動創建的, Product Key Count 是我們在這里手動創建的)
使用 SQL 語句在數據倉庫中直接查詢。
SELECT DISTINCT
dpc.EnglishProductCategoryName AS 'Category',
SUM(fact.SalesAmount) OVER(PARTITION BY dpc.ProductCategoryKey) AS 'Reseller Sales Amount',
COUNT(*) OVER(PARTITION BY dpc.ProductCategoryKey) AS 'Reseller Sales Count',
MAX(fact.SalesAmount) OVER(PARTITION BY dpc.ProductCategoryKey) AS 'MAX Sales Amount'
FROM FactResellerSales AS fact
LEFT JOIN DimProduct AS dp
ON fact.ProductKey = dp.ProductKey
INNER JOIN DimProductSubcategory AS dps
ON dp.ProductSubcategoryKey = dps.ProductSubcategoryKey
INNER JOIN DimProductCategory AS dpc
ON dps.ProductCategoryKey = dpc.ProductCategoryKey
結果是一樣的。
再來按年瀏覽一下訂單數量和訂單明細的數量,例如 CY2005 年共有366個訂單,366個訂單共計 4138 個訂單明細。
在數據倉庫中直接查詢 Fact 表和 Dimension 表的結果也是一樣的。
SELECT DISTINCT
dt.CalendarYearKey,
(
SELECT COUNT(DISTINCT f.SalesOrderNumber) AS OrderCountByYear
FROM FactResellerSales AS f
LEFT JOIN DimDate AS d
ON f.OrderDateKey = d.DateKey
WHERE d.CalendarYearKey = dt.CalendarYearKey
GROUP BY d.CalendarYearKey
)AS OrderNumberCount,
COUNT(*) OVER(PARTITION BY CalendarYearKey) AS OrderDetailCount
FROM FactResellerSales AS fact
LEFT JOIN DimDate AS dt
ON fact.OrderDateKey = dt.DateKey
ORDER BY dt.CalendarYearKey
另外,要補充一點。像 BI 項目的測試與其它項目的測試不太一樣,因為更多的關於數據方面的清理,整理與轉換。但是在數據倉庫級別和 Cube 級別的數據比較,從我的這篇文章中應該可以看到一些方法與技巧。也就是無論是數據倉庫還是多維分析數據庫它們都是數據的一個容器,因此可以通過 SQL 語句直接在數據倉庫中查詢最原始的數據,然后與從 Cube 中無論從 MDX 還是 Excel 中出來的維度關聯事實數據進行對比就可以了。
原因很簡單,一種是基於數據倉庫的 SQL 查詢 (數據倉庫 - Select 查詢結果集) , 一種是基於數據倉庫的多維數據集 (數據倉庫 - Cube - Excel 或者 MDX),基於的都是同一個數據源,那么就比較它們各自的查詢結果就知道數據是否是預期的了。
以后有時間專門再寫一篇有關 BI 項目的測試過程,階段分解以及測試的方法等。
更多 BI 文章請參看 BI 系列隨筆列表 (SSIS, SSRS, SSAS, MDX, SQL Server) 如果覺得這篇文章看了對您有幫助,請幫助推薦,以方便他人在 BIWORK 博客推薦欄中快速看到這些文章。