<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>简单生活 -- Kevin Yang的博客 &#187; BI/数据库</title>
	<atom:link href="http://www.imkevinyang.com/categories/techarticles/businessintelligence/feed" rel="self" type="application/rss+xml" />
	<link>http://www.imkevinyang.com</link>
	<description>It&#039;s all about sharing</description>
	<lastBuildDate>Sun, 05 Feb 2012 15:37:14 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Sql Server重命名所有外键约束</title>
		<link>http://www.imkevinyang.com/2010/08/sql-server%e9%87%8d%e5%91%bd%e5%90%8d%e6%89%80%e6%9c%89%e5%a4%96%e9%94%ae%e7%ba%a6%e6%9d%9f.html</link>
		<comments>http://www.imkevinyang.com/2010/08/sql-server%e9%87%8d%e5%91%bd%e5%90%8d%e6%89%80%e6%9c%89%e5%a4%96%e9%94%ae%e7%ba%a6%e6%9d%9f.html#comments</comments>
		<pubDate>Mon, 02 Aug 2010 08:00:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[DMV]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[外键约束]]></category>
		<category><![CDATA[存储过程]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[重命名]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2010/08/sql-server%e9%87%8d%e5%91%bd%e5%90%8d%e6%89%80%e6%9c%89%e5%a4%96%e9%94%ae%e7%ba%a6%e6%9d%9f.html</guid>
		<description><![CDATA[<p>公司服务器上的数据库原先是采用PowerDesigner设计的，那些外键约束的命名非常难看，并且也和后来在SSMS中额外添加的外键约束命名规则不一致，因此我想遍历数据库的所有外键约束，找到外键约束的相关对象，然后重新生成一致的命名。</p>
<p>我采用的命名规则是：</p>
<blockquote><p>FK_ForeignTable_PrimaryT&#8230;</p></blockquote>]]></description>
			<content:encoded><![CDATA[<p>公司服务器上的数据库原先是采用PowerDesigner设计的，那些外键约束的命名非常难看，并且也和后来在SSMS中额外添加的外键约束命名规则不一致，因此我想遍历数据库的所有外键约束，找到外键约束的相关对象，然后重新生成一致的命名。</p>
<p>我采用的命名规则是：</p>
<blockquote><p>FK_ForeignTable_PrimaryTable_On_ForeignColumn</p>
</blockquote>
<p>直白的翻译就是，ForeignTable在ForeignColumn列上引用了PrimaryTable的主键。</p>
<p>Sql Server提供了很多动态管理视图（Dynamic management views，DMV）和存储过程，方便我们对数据库进行维护。这里我用到了以下两个sys.foreign_key_columns（包含外键约束完整信息）和sys.objects（数据库对象信息）这两个DMV以及sp_rename执行重命名的系统存储过程。代码如下：</p>
<pre class="brush: sql">declare fkcur cursor for
select
OBJECT_NAME(col.constraint_object_id) as FKConstraintName
,fkTable.name as FKTable
,fkCol.name as FKColumn
,pkTable.name as PKTable
,pkCol.name as PKColumn
from sys.foreign_key_columns col
-- 外键约束是建立在外键表上的，
-- 因此foreign_key_columns表中的parent_object_id和parent_column_id分别表示外键表和外键列
inner join sys.objects fkTable
    on fkTable.object_id = col.parent_object_id
inner join sys.columns fkCol
    on fkCol.column_id = col.parent_column_id
    and fkCol.object_id = fkTable.object_id
-- foreign_key_columns表中的referenced_object_id和referenced_column_id分别指向
-- 外键约束的主键表对象以及主键列
inner join sys.objects pkTable
    on pkTable.object_id = col.referenced_object_id
inner join sys.columns pkCol
    on pkCol.column_id = col.referenced_column_id
    and pkCol.object_id = pkTable.object_id
order by OBJECT_NAME(col.constraint_object_id)

open fkcur
declare @constraintName nvarchar(128)
declare @fkTable nvarchar(64)
declare @fkColumn nvarchar(64)
declare @pkTable nvarchar(64)
declare @pkColumn nvarchar(64)
declare @newConstraintName nvarchar(128)

fetch next from fkcur
into @constraintName,@fkTable,@fkColumn,@pkTable,@pkColumn
while @@FETCH_STATUS = 0
begin
    set @newConstraintName = 'FK_'+@fkTable+'_'+@pkTable+'_On_'+@fkColumn
    exec sp_rename @constraintName,@newConstraintName,'Object'

    fetch next from fkcur
    into @constraintName,@fkTable,@fkColumn,@pkTable,@pkColumn
end
close fkcur
deallocate fkcur</pre>
<p style="text-align: right">——<a title="Sql Server重命名所有外键约束" href="http://www.imkevinyang.com/2010/08/sql-server%E9%87%8D%E5%91%BD%E5%90%8D%E6%89%80%E6%9C%89%E5%A4%96%E9%94%AE%E7%BA%A6%E6%9D%9F.html"><em>Kevin Yang</em></a></p>

	标签：<a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/dmv" title="DMV" rel="tag">DMV</a>, <a href="http://www.imkevinyang.com/tags/sql-server" title="SQL Server" rel="tag">SQL Server</a>, <a href="http://www.imkevinyang.com/tags/%e5%a4%96%e9%94%ae%e7%ba%a6%e6%9d%9f" title="外键约束" rel="tag">外键约束</a>, <a href="http://www.imkevinyang.com/tags/%e5%ad%98%e5%82%a8%e8%bf%87%e7%a8%8b" title="存储过程" rel="tag">存储过程</a>, <a href="http://www.imkevinyang.com/tags/%e6%95%b0%e6%8d%ae%e5%ba%93" title="数据库" rel="tag">数据库</a>, <a href="http://www.imkevinyang.com/tags/%e9%87%8d%e5%91%bd%e5%90%8d" title="重命名" rel="tag">重命名</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/05/sql-server%e4%b8%ad%e4%bf%ae%e6%94%b9%e8%87%aa%e5%a2%9e%e9%95%bf%e5%88%97%e7%bb%8f%e5%b8%b8%e9%9c%80%e8%a6%81%e7%94%a8%e5%88%b0%e7%9a%84%e9%85%8d%e7%bd%ae.html" title="Sql Server中修改自增长列经常需要用到的配置 (2009/05/24)">Sql Server中修改自增长列经常需要用到的配置</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html" title="Sql Tips——Update语句也使用表别名(Table Alias) (2010/07/02)">Sql Tips——Update语句也使用表别名(Table Alias)</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/05/ssis%e8%b0%83%e7%94%a8%e5%ad%98%e5%82%a8%e8%bf%87%e7%a8%8b%e5%a4%b1%e8%b4%a5.html" title="SSIS调用存储过程失败 (2010/05/23)">SSIS调用存储过程失败</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/10/%e5%85%a8%e5%8d%8a%e8%a7%92%e7%a9%ba%e6%a0%bc%e5%af%bc%e8%87%b4%e7%9a%84analysis-service%e5%a4%84%e7%90%86%e9%94%99%e8%af%af.html" title="全半角空格导致的Analysis Services处理错误 (2009/10/09)">全半角空格导致的Analysis Services处理错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e9%87%8a%e6%94%besql-server%e5%8d%a0%e7%94%a8%e7%9a%84%e5%86%85%e5%ad%98.html" title="释放SQL Server占用的内存 (2009/09/01)">释放SQL Server占用的内存</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2010/08/sql-server%e9%87%8d%e5%91%bd%e5%90%8d%e6%89%80%e6%9c%89%e5%a4%96%e9%94%ae%e7%ba%a6%e6%9d%9f.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>SSAS处理时&#8220;找不到属性键&#8221;的解决办法</title>
		<link>http://www.imkevinyang.com/2010/07/ssas%e5%a4%84%e7%90%86%e6%97%b6%e6%89%be%e4%b8%8d%e5%88%b0%e5%b1%9e%e6%80%a7%e9%94%ae%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95.html</link>
		<comments>http://www.imkevinyang.com/2010/07/ssas%e5%a4%84%e7%90%86%e6%97%b6%e6%89%be%e4%b8%8d%e5%88%b0%e5%b1%9e%e6%80%a7%e9%94%ae%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95.html#comments</comments>
		<pubDate>Sun, 18 Jul 2010 17:07:20 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[SSAS]]></category>
		<category><![CDATA[处理异常]]></category>
		<category><![CDATA[属性键]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2010/07/ssas%e5%a4%84%e7%90%86%e6%97%b6%e6%89%be%e4%b8%8d%e5%88%b0%e5%b1%9e%e6%80%a7%e9%94%ae%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95.html</guid>
		<description><![CDATA[<p>在SSAS中，经常会遇到“Attribute key not found（找不到属性键）”的错误，这种错误通常是由于某个维度属性（Dimension Attribute）的<font face="Aparajita">数</font>据没能从Sql Server导入到Analysis Services中(处理这个维度属性的过程倒是不会出错)，而维度关键属性（Dimens&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>在SSAS中，经常会遇到“Attribute key not found（找不到属性键）”的错误，这种错误通常是由于某个维度属性（Dimension Attribute）的<font face="Aparajita">数</font>据没能从Sql Server导入到Analysis Services中(处理这个维度属性的过程倒是不会出错)，而维度关键属性（Dimension Key Attribute）处理时又需要这些数据，因而引发了这个“找不到属性键”的错误。这么讲可能有些抽象，你可以看我以前写的文章<a href="http://www.imkevinyang.com/2009/10/%E5%85%A8%E5%8D%8A%E8%A7%92%E7%A9%BA%E6%A0%BC%E5%AF%BC%E8%87%B4%E7%9A%84analysis-service%E5%A4%84%E7%90%86%E9%94%99%E8%AF%AF.html">全半角空格导致的Analysis Services处理错误</a>，里头有具体的案例。</p>
<p>解决这种问题就需要定位到出问题的数据。而生产环境中数据量一般会比较大，我们不大可能检查所有数据来发现可疑数据，这个时候，SSAS给出的错误提示就很有帮助了。</p>
<p>通常遇到处理异常，SSAS会有两种错误信息提示，一种是</p>
<blockquote><p>Errors in the OLAP storage engine: The attribute key cannot be found: Table: TableName, Column: ColumnName1, Value: Value1. Table: TableName, Column: ColumnName2, Value: Value2.</p>
</blockquote>
<p>这个错误提示会给出数据源中出错的数据，是在哪个表的哪个字段哪个值出的问题。</p>
<p>还有一个是</p>
<blockquote><p>Errors in the OLAP storage engine: The record was skipped because the attribute key was not found. Attribute: generated attribute X of Dimension: DimensionName from Database: DatabaseName, Cube: CubeName, Measure Group: MeasureGroupName, Partition: PartitionName, Record: <font color="#ff0000">RecordNumber</font>.</p>
</blockquote>
<p>这个错误信息给出的是Analysis数据库中出错的位置，是哪个AS数据库的哪个数据立方体的哪个维度的哪个维度属性出的问题，以及出错条目编号是多少。</p>
<p>如果出错数据比较好辨认的话，那么我们可以直接在源数据库中使用like操作符查询相关的条目即可。例如下面这个例子：</p>
<p><img style="display: inline" class="wlDisabledImage" title="image[36]" alt="image[36]" src="http://www.imkevinyang.com/wp-content/uploads/2010/07/image36.png" width="534" height="28" /></p>
<p>我们可以很快将出错数据锁定在一个较小的范围。但是如果错误信息像下面这样：</p>
<p><img style="margin: 0px; display: inline" class="wlDisabledImage" title="image" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/07/image1.png" width="279" height="26" /></p>
<p>你可能就没那么好定位了，这个时候我们就需要第二个错误提示的帮助了。</p>
<p>为了在处理失败时显示第二个错误提示，我们需要修改维度的ErrorConfiguration属性。打开维度的属性面板，展开ErrorConfiguration中的KeyNotFound，BIDS中如果你新建一个维度，那么默认配置会像下面这样：</p>
<p><img style="margin: 0px; display: inline" class="wlDisabledImage" title="image" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/07/image2.png" width="343" height="198" /></p>
<p>如果处理失败，是不会显示第二个错误提示的。我们需要将KeyNotFound设置为ReportAndContinue，或者直接把整个ErrorConfiguration从(custom)改成(default)。</p>
<p><img style="margin: 0px; display: inline" class="wlDisabledImage" title="image" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/07/image3.png" width="349" height="202" /></p>
<p>这样我们就能得到第二个错误提示了，第二个错误提示中有一个“记录(Record)”的编号，那么这个编号代表什么含义呢？</p>
<p><img style="margin: 0px; display: inline" class="wlDisabledImage" title="image" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/07/image4.png" width="475" height="49" /></p>
<p>我一开始直觉的认为是EmployeeKey的主键键值，后来发现不对，于是猜测是处理时执行的Sql查询返回的结果集的行编号，后来发现又错了。</p>
<p><img style="margin: 0px; display: inline" class="wlDisabledImage" title="image" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/07/image5.png" width="588" height="186" /></p>
<p>在经过一番测试后发现，错误提示中的“记录”编号，确实是和Sql查询返回的条目的行编号有关，但却有一定的偏移，一般情况下这个偏移值为1，也就是说，假设SSAS告诉你“记录”7出错了，那么就是第6行的数据出错了。</p>
<p><img style="margin: 0px; display: inline" class="wlDisabledImage" title="image" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/07/image6.png" width="262" height="158" /></p>
<p>但有时候这个偏移不一定是1，有可能是2。至于规律和原因我暂时没找到。所以你只需要把出问题的维度属性相关的Sql查询放到Sql Server中运行一遍，然后根据错误提示中的“记录”号找到那附近的几行数据，一般就可以成功定位到错误数据了。</p>
<p style="text-align: right">——<a title="SSAS处理时“找不到属性键”的解决办法" href="http://www.imkevinyang.com/2010/07/ssas%E5%A4%84%E7%90%86%E6%97%B6%E6%89%BE%E4%B8%8D%E5%88%B0%E5%B1%9E%E6%80%A7%E9%94%AE%E7%9A%84%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95.html"><em>Kevin Yang</em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/analysis-services" title="Analysis Services" rel="tag">Analysis Services</a>, <a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/ssas" title="SSAS" rel="tag">SSAS</a>, <a href="http://www.imkevinyang.com/tags/%e5%a4%84%e7%90%86%e5%bc%82%e5%b8%b8" title="处理异常" rel="tag">处理异常</a>, <a href="http://www.imkevinyang.com/tags/%e5%b1%9e%e6%80%a7%e9%94%ae" title="属性键" rel="tag">属性键</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2010/05/64%e4%bd%8d%e7%b3%bb%e7%bb%9f%e4%b8%8biis7-isapi%e5%a4%84%e7%90%86%e5%99%a8%e5%8a%a0%e8%bd%bd%e5%a4%b1%e8%b4%a5.html" title="64位系统下IIS7 ISAPI处理器加载失败 (2010/05/05)">64位系统下IIS7 ISAPI处理器加载失败</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5.html" title="Analysis Services 2005 OLAP设计最佳实践 (2009/04/02)">Analysis Services 2005 OLAP设计最佳实践</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/04/analysis-services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html" title="Analysis Services：你应该使用多对多维度吗？ (2010/04/12)">Analysis Services：你应该使用多对多维度吗？</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/bids%e5%af%b9%e4%ba%8e%e7%bb%b4%e5%ba%a6%e5%b1%9e%e6%80%a7%e9%94%ae%e4%b8%ba%e5%8f%af%e5%8f%98%e9%95%bf%e5%88%97%e6%97%b6%e5%ad%98%e5%9c%a8%e7%9a%84bug.html" title="BIDS对于维度属性键为可变长列时存在的Bug (2009/03/22)">BIDS对于维度属性键为可变长列时存在的Bug</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/bids%e9%83%a8%e7%bd%b2%e6%97%b6%e5%87%ba%e7%8e%b0%e5%85%83%e6%95%b0%e6%8d%ae%e7%ae%a1%e7%90%86%e5%99%a8%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af.html" title="BIDS部署时出现元数据管理器发生错误 (2009/03/13)">BIDS部署时出现元数据管理器发生错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/olap%e4%b8%ad%e7%9a%84averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f.html" title="OLAP中的AverageOfChildren聚合方式 (2009/08/10)">OLAP中的AverageOfChildren聚合方式</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/10/%e5%85%a8%e5%8d%8a%e8%a7%92%e7%a9%ba%e6%a0%bc%e5%af%bc%e8%87%b4%e7%9a%84analysis-service%e5%a4%84%e7%90%86%e9%94%99%e8%af%af.html" title="全半角空格导致的Analysis Services处理错误 (2009/10/09)">全半角空格导致的Analysis Services处理错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/%e6%9d%83%e9%99%90%e5%af%bc%e8%87%b4%e7%9a%84analysis%e6%80%a7%e8%83%bd%e8%ae%a1%e6%95%b0%e5%99%a8%e5%9c%a8vistawin2008%e4%b8%8b%e5%a4%b1%e6%95%88%e7%9a%84%e9%97%ae%e9%a2%98.html" title="权限不足导致的Analysis性能计数器在Vista/win2008下失效的问题 (2009/11/12)">权限不足导致的Analysis性能计数器在Vista/win2008下失效的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3%e7%bb%b4%e5%ba%a6%e6%88%90%e5%91%98%e4%b8%ad%e7%9a%84%e9%9d%9e%e6%b3%95xml%e5%ad%97%e7%ac%a6%e5%af%bc%e8%87%b4%e7%9a%84%e6%9f%a5%e8%af%a2%e9%94%99%e8%af%af-2.html" title="解决维度成员中的非法Xml字符导致的查询错误 (2009/09/19)">解决维度成员中的非法Xml字符导致的查询错误</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2010/07/ssas%e5%a4%84%e7%90%86%e6%97%b6%e6%89%be%e4%b8%8d%e5%88%b0%e5%b1%9e%e6%80%a7%e9%94%ae%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Sql Tips——Update语句也使用表别名(Table Alias)</title>
		<link>http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html</link>
		<comments>http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html#comments</comments>
		<pubDate>Thu, 01 Jul 2010 16:11:21 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[其他随笔]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Update]]></category>
		<category><![CDATA[数据库]]></category>
		<category><![CDATA[表别名]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html</guid>
		<description><![CDATA[<p>在编写Sql脚本时通过表别名可以大大缩减Sql代码，同时表别名也是解决同表多次引用的手段之一。在select中使用表别名大家应该都很熟悉了：</p>
<pre class="brush: sql">select * from TableA as A inner join TableB as B on A.Key1 = B.Key1</pre>
<p>但是在Update中使用表别名可能就没那么多人知道了。&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>在编写Sql脚本时通过表别名可以大大缩减Sql代码，同时表别名也是解决同表多次引用的手段之一。在select中使用表别名大家应该都很熟悉了：</p>
<pre class="brush: sql">select * from TableA as A inner join TableB as B on A.Key1 = B.Key1</pre>
<p>但是在Update中使用表别名可能就没那么多人知道了。</p>
<pre class="brush: sql">update T
set T.Key1 = 'xxxx'
from TableA T</pre>
<p>这些天在写Sql Update脚本的时候需要引用两次同个表对象，如果直接像下面这样引用两次TableA则会抛出“The multi-part identifier ‘TableA.Index’ could not be bound”的错误。这是因为Sql引擎无法知道你在where子句中的TableA到底指的是要Update的表还是from后面的表。</p>
<pre class="brush: sql">update TableA
set TableA.NextKey = T.Key
from TableA T
where T.Index = TableA.Index + 1</pre>
<p>如果不对Update后面的TableA使用别名的话，我们只能通过以下方法来实现。</p>
<pre class="brush: sql">update TableA
set TableA.NextKey = T.Key
from
(
  select * from TableA
)T
where T.Index = TableA.Index + 1</pre>
<p>使用别名可以得到更简洁的写法:</p>
<pre class="brush: sql">update T1
set T1.NextKey = T2.Key
from TableA T1, TableA T2
whereT2.Index = T1.Index + 1</pre>
<p style="text-align: right;">——<a title="Sql Tips——Update语句也使用表别名(Table Alias)" href="http://www.imkevinyang.com/2010/07/sql-tipsupdate%E8%AF%AD%E5%8F%A5%E4%B9%9F%E4%BD%BF%E7%94%A8%E8%A1%A8%E5%88%AB%E5%90%8Dtable-alias.html" target="_self"><em>Kevin Yang</em></a></p>

	标签：<a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/sql" title="SQL" rel="tag">SQL</a>, <a href="http://www.imkevinyang.com/tags/tips" title="Tips" rel="tag">Tips</a>, <a href="http://www.imkevinyang.com/tags/update" title="Update" rel="tag">Update</a>, <a href="http://www.imkevinyang.com/categories/techarticles/othertecharticles" title="其他随笔" rel="tag">其他随笔</a>, <a href="http://www.imkevinyang.com/tags/%e6%95%b0%e6%8d%ae%e5%ba%93" title="数据库" rel="tag">数据库</a>, <a href="http://www.imkevinyang.com/tags/%e8%a1%a8%e5%88%ab%e5%90%8d" title="表别名" rel="tag">表别名</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/09/blend%e5%b0%8f%e8%b4%b4%e5%a3%ab%e6%94%b9%e5%8f%98%e9%bc%a0%e6%a0%87%e6%bb%9a%e8%bd%ae%e7%9a%84%e9%bb%98%e8%ae%a4%e8%a1%8c%e4%b8%ba-2.html" title="Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为 (2009/09/18)">Blend小贴士&mdash;&mdash;改变鼠标滚轮的默认行为</a> </li>
	<li><a href="http://www.imkevinyang.com/2011/06/onenote-tips-%e6%b7%b7%e5%90%88%e4%bd%bf%e7%94%a8%e4%b8%ad%e8%8b%b1%e6%96%87%e5%ad%97%e4%bd%93.html" title="OneNote Tips — 混合使用中英文字体 (2011/06/16)">OneNote Tips — 混合使用中英文字体</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/sql-server%e4%b8%ad%e4%bf%ae%e6%94%b9%e8%87%aa%e5%a2%9e%e9%95%bf%e5%88%97%e7%bb%8f%e5%b8%b8%e9%9c%80%e8%a6%81%e7%94%a8%e5%88%b0%e7%9a%84%e9%85%8d%e7%bd%ae.html" title="Sql Server中修改自增长列经常需要用到的配置 (2009/05/24)">Sql Server中修改自增长列经常需要用到的配置</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/08/sql-server%e9%87%8d%e5%91%bd%e5%90%8d%e6%89%80%e6%9c%89%e5%a4%96%e9%94%ae%e7%ba%a6%e6%9d%9f.html" title="Sql Server重命名所有外键约束 (2010/08/02)">Sql Server重命名所有外键约束</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/05/ssis%e8%b0%83%e7%94%a8%e5%ad%98%e5%82%a8%e8%bf%87%e7%a8%8b%e5%a4%b1%e8%b4%a5.html" title="SSIS调用存储过程失败 (2010/05/23)">SSIS调用存储过程失败</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/visual-studio%e5%b0%8f%e8%b4%b4%e5%a3%ab%e5%8a%a0%e4%ba%86try-catch%e4%b9%9f%e8%83%bd%e8%87%aa%e5%8a%a8%e5%ae%9a%e4%bd%8d%e5%88%b0%e5%bc%82%e5%b8%b8%e4%bb%a3%e7%a0%81.html" title="Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码 (2009/09/18)">Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e9%87%8a%e6%94%besql-server%e5%8d%a0%e7%94%a8%e7%9a%84%e5%86%85%e5%ad%98.html" title="释放SQL Server占用的内存 (2009/09/01)">释放SQL Server占用的内存</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2010/07/sql-tipsupdate%e8%af%ad%e5%8f%a5%e4%b9%9f%e4%bd%bf%e7%94%a8%e8%a1%a8%e5%88%ab%e5%90%8dtable-alias.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Analysis Services：你应该使用多对多维度吗？</title>
		<link>http://www.imkevinyang.com/2010/04/analysis-services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html</link>
		<comments>http://www.imkevinyang.com/2010/04/analysis-services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html#comments</comments>
		<pubDate>Sun, 11 Apr 2010 17:29:58 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[OLAP]]></category>
		<category><![CDATA[多对多]]></category>
		<category><![CDATA[度量组]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[维度]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2010/04/analysis-services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html</guid>
		<description><![CDATA[如果你是一个初学者，请注意，这篇文章并不是告诉你不要在Analysis Services中使用多对多（m:n）维度。事实上，这是一个非常棒的功能，它允许你将多个维度成员和多条事实数据之间建立关联关系。在很多商业领域，从零售行业到会计行业到医疗行业，多对多关系被大量使用着。但有时在处理多对多关系时，如果遇到大规模数据量，可能会遇到数据查询性能问题以及数据精准性问题。这篇技术文章就是为了说明多对多关系背后的工作原理和适合的商业应用场景，以及应用多对多关系可能带来的数据精准性问题。]]></description>
			<content:encoded><![CDATA[<div class="statement">
<p>作者：Denny Lee</p>
<p>译者：<a href="http://www.imkevinyang.com/2010/04/Analysis%20Services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html">Kevin Yang</a></p>
<p>英文链接：<a title="http://sqlcat.com/technicalnotes/archive/2008/02/11/analysis-services-should-you-use-many-to-many-dimensions.aspx" href="http://sqlcat.com/technicalnotes/archive/2008/02/11/analysis-services-should-you-use-many-to-many-dimensions.aspx">http://sqlcat.com/technicalnotes/archive/2008/02/11/analysis-services-should-you-use-many-to-many-dimensions.aspx</a></p>
</div>
<p>如果你是一个初学者，请注意，这篇文章并不是告诉你不要在Analysis Services中使用多对多（m:n）维度。事实上，这是一个非常棒的功能，它允许你将多个维度成员和多条事实数据之间建立关联关系。在很多商业领域，从零售行业到会计行业到医疗行业，多对多关系被大量使用着。但有时在处理多对多关系时，如果遇到大规模数据量，可能会遇到数据查询性能问题以及数据精准性问题。这篇技术文章就是为了说明多对多关系背后的工作原理和适合的商业应用场景，以及应用多对多关系可能带来的数据精准性问题。</p>
<h2>相关背景</h2>
<p>我在我之前的博文“<a href="http://denster.spaces.live.com/blog/cns%21125D53A08EC75357%21283.entry">How to handle many-to-many relationships in Yukon?</a>”中提到的应用多对多关系的一个例子是地理维度。但现在我们将使用Adventure Works DW OLAP这个示例（相关代码在Codeplex的<a href="http://www.codeplex.com/MSFTDBProdSamples/Release/ProjectReleases.aspx?ReleaseId=4004">SQL Server 2005 SP2 Sample Databases</a>上可以下载到）。</p>
<p>打开AdventureWorks数据库，在AdventureWorks数据立方体的“维度使用”标签卡下，我们可以看到[Sales Reason]维度通过[Sales Reasons]中间度量组关联到了[Internet Sales]度量组（图中没有显示）上。[Sales Reasons]旁边放了一个数学上用于表示“无穷”的图标，说明这个关系和常规维度（就像[Source Currency]维度和[Source Currency Code]度量组的关系）不一样，这是一个多对多关系。</p>
<p><a href="http://sqlcat.com/blogs/technicalnotes/WindowsLiveWriter/AnalysisServicesShouldyouusemanytomanydi_8E4E/image_2.png"><img style="display: inline; border: 0px;" title="在BIDS中[Sales Reason]和[Internet Sales]的多对多关系图" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/clip_image001.png" border="0" alt="在BIDS中[Sales Reason]和[Internet Sales]的多对多关系图" width="351" height="71" /></a></p>
<p>单击[Sales Reasons]度量组，会弹出一个设计维度-度量组关联的对话框（见下图），在这里，你会注意到，[Sales Reason]和[Internet Sales]这两者之间的关系是多对多关系，并且，连接[Sales Reason]维度和[Internet Sales]度量组的中间度量组是[Sales Reasons]。</p>
<p><a href="http://sqlcat.com/blogs/technicalnotes/WindowsLiveWriter/AnalysisServicesShouldyouusemanytomanydi_8E4E/image_4.png"><img style="display: inline; border: 0px;" title="在BIDS中设计多对多关系" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/clip_image002.png" border="0" alt="在BIDS中设计多对多关系" width="461" height="272" /></a></p>
<p>以下这张图说明了在这个场景中使用多对多维度的目的。我们希望把多个销售成功因素（例如价格很低，展示效果不错，或者其他因素）和一笔销售订单关联起来。</p>
<p><a href="http://sqlcat.com/blogs/technicalnotes/WindowsLiveWriter/AnalysisServicesShouldyouusemanytomanydi_8E4E/image_6.png"><img style="display: inline; border: 0px;" title="销售因素和销售情况之间的维度-度量组关系图" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/clip_image003.png" border="0" alt="销售因素和销售情况之间的维度-度量组关系图" width="382" height="195" /></a></p>
<p>举个例子，John购买了一个高清电视机（对应事实表Internet Sales的一条记录），是因为最近正在大减价（销售成功因素：价格）并且超级联赛杯快要开始了（销售成功因素：其他）。</p>
<h2>应用场景示例</h2>
<p>我们回过头来看看[Adventure Works]的Sql以及Olap数据库的设计，这样可以更好地从技术上去理解多对多关系。在之前我们看到的[Adventure Works DW]Olap数据库中包含了[Internet Sales]和[Sales Reasons]度量组，以及[Sales Reason]维度。在AdventureWorks的Sql数据库中，这几个对象分别对应着FactInternetSales、FactInternetSalesReasons以及DimSalesReason表。</p>
<p>继续我们上面的例子，为了简单起见，我们只关注两条数据(SalesOrderNumber = 'SO69868', SalesOrderLineNumber = 2) 和(SalesOrderNumber = 'SO75088', SalesOrderLineNumber = 3)。</p>
<p>Sql查询为：</p>
<pre class="csharpcode"><span class="kwrd">select</span> SalesOrderNumber, SalesOrderLineNumber, SalesAmount
<span class="kwrd">from</span> FactInternetSales
<span class="kwrd">where</span> (SalesOrderNumber = <span class="str">'SO69868'</span> <span class="kwrd">and</span> SalesOrderLineNumber = 2) <span class="kwrd">or</span>
(SalesOrderNumber = <span class="str">'SO75088'</span> <span class="kwrd">and</span> SalesOrderLineNumber = 3)</pre>
<p>结果集：</p>
<p><img style="display: inline; border: 0px;" title="两笔订单交易数据" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image.png" border="0" alt="两笔订单交易数据" width="305" height="66" /></p>
<p>当你开始考虑FactInternetSales和FactInternetSalesReasons的多对多关系，需要将SalesReason表也加进来，你需要执行以下Sql查询：</p>
<pre class="csharpcode"><span class="kwrd">select</span> a.SalesOrderNumber, a.SalesOrderLineNumber, a.SalesAmount,
c.SalesReasonKey, c.SalesReasonName, c.SalesReasonReasonType
<span class="kwrd">from</span> FactInternetSales a
<span class="kwrd">inner</span> <span class="kwrd">join</span> FactInternetSalesReason b
<span class="kwrd">on</span> b.SalesOrderNumber = a.SalesOrderNumber
<span class="kwrd">and</span> b.SalesOrderLineNumber = a.SalesOrderLineNumber
<span class="kwrd">inner</span> <span class="kwrd">join</span> DimSalesReason c
<span class="kwrd">on</span> c.SalesReasonKey = b.SalesReasonKey
<span class="kwrd">where</span> (a.SalesOrderNumber = <span class="str">'SO69868'</span> <span class="kwrd">and</span> a.SalesOrderLineNumber = 2) <span class="kwrd">or</span>
(a.SalesOrderNumber = <span class="str">'SO75088'</span> <span class="kwrd">and</span> a.SalesOrderLineNumber = 3)</pre>
<p>新的结果集如下：</p>
<p><img style="display: inline; border: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image1.png" border="0" alt="image" width="566" height="82" /></p>
<p>从这两张表中你也可以看出，通过中间表FactInternetSalesReasons，你可以将多条销售成功因素记录关联到同一笔销售订单上。例如上述的SO75088订单，金额为$34.99，关联着“价格”和“其他”两条销售成功因素记录。</p>
<h2>多对多维度的优势</h2>
<p>这种通过中间表关联的优势在于，你可以将多个维度成员和一个事实表记录关联到一起。当你想要汇总这些值的时候，优势就体现出来了。例如，当你使用[Sales Reason]维度去查询[Internet Sales]度量组的时候，可以得到以下结果：</p>
<pre class="csharpcode"><span class="kwrd">select</span> {[Measures].[Internet Sales Amount]} <span class="kwrd">on</span> columns,
{[Sales Reason].[Sales Reason].members} <span class="kwrd">on</span> <span class="kwrd">rows</span>
<span class="kwrd">from</span> [Adventure Works]</pre>
<p><img style="display: inline; border: 0px;" title="不同销售成功因素对于销售的影响" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image2.png" border="0" alt="不同销售成功因素对于销售的影响" width="416" height="259" /></p>
<p>上述结果集里头，由于[Price]和[Others]这两个销售成功因素都是SO75088这个订单成功的因素，因此其销售额都包含了SO75088订单的金额。而更不错的是，你现在有了一个[All Sales Reasons]的成员，用来表示总的销售金额$29,358,677.22。</p>
<p>你如果直接查询[Measures].[Internet Sales Amount]指标，得到的结果也是一样的。</p>
<pre class="csharpcode"><span class="kwrd">select</span> {[Measures].[Internet Sales Amount]} <span class="kwrd">on</span> columns
<span class="kwrd">from</span> [Adventure Works]</pre>
<h2>数据精准性问题</h2>
<p>使用多对多维度的一个潜在问题就是数据重复计算，特别是当用户没能很好理解多对多背后原理的话，更有可能出现这种情况。例如，我们执行以下MDX查询：</p>
<pre class="csharpcode"><span class="kwrd">select</span> {[Measures].[Internet Sales Amount]} <span class="kwrd">on</span> columns,
{[Sales Reason].[Sales Reason].children} <span class="kwrd">on</span> <span class="kwrd">rows</span>
<span class="kwrd">from</span> [Adventure Works]</pre>
<p>得到以下结果：</p>
<p><img style="display: inline; border: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image3.png" border="0" alt="image" width="383" height="235" /></p>
<p>得到这样的数据之后，用户可能会直接使用上述的数据相加来计算总的销售金额，从而得到以下结果：</p>
<p><img style="display: inline; border: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image4.png" border="0" alt="image" width="385" height="256" /></p>
<p>注意，这里的总和$30,856,531.52和前面提到的[All Sales Reasons]成员的汇总值$29,358,677.22很不一样，相差了$1,497,854.30，如果你从事金融方面工作的话，这个差别应该是足够明显了。</p>
<p>问题的复杂之处在于，当你应用多对多维度的时候，你无从知道那些成员会被重复计算，因为任何一单销售都有可能和任何一个销售成功因素关联。例如用户有可能直接把[Other]和[Price]成员的销售额相加，得到因为这两个原因而成交的订单销售额情况$11,224,325.90。但是这样的结果是错误的，因为有一些销售订单同时包含了这两个销售成功因素。因此总和应该是小于$11,224,325.90的。</p>
<h2>有别的解决办法吗？</h2>
<p>“是否应该使用多对多维度”，你主要需要考虑两个方面的问题：性能和数据精准性。</p>
<h3>性能</h3>
<p>在<a href="http://download.microsoft.com/download/8/5/e/85eea4fa-b3bb-4426-97d0-7f7151b2011c/ssas2005perfguide.doc">Analysis Services 性能指南</a>中提到，有时候应用多对多是出于性能的考虑，其中一个情形就是对Distinct Count类型的度量进行泛化。使用多对多维度可以让你通过Analysis Services的sum、count、max、min等运算符实现和Distinct Count一样的逻辑。为了计算Distinct Count或者Sum，Analysis Services存储引擎需要直接对最小粒度的数据做转换。这是因为，当一个查询涉及到多对多维度的时候，聚合结果是在查询期间通过目标度量组和中间度量组在属性级别上完成的。查询的过程相对比较消耗CPU和内存。</p>
<p>多对多的性能考虑主要包括以下几个方面：</p>
<ul>
<li>因为查询涉及到多对多维度，会在目标度量分组和中间度量分组之间生成一个Join连接，因此降低中间度量组的表大小（通常小于1百万行数据）可以提高查询性能。细节参考：<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=3494E712-C90B-4A4E-AD45-01009C15C665&amp;displaylang=en">Analysis Services Many-to-Many Dimensions: Query Performance Optimization Techniques</a> 白皮书。</li>
<li>目标度量组和中间度量组之间的连接是哈希连接，因此完成此项操作非常消耗内存。</li>
<li>和Distinct Count不同，多对多关系不能被预聚合（虽然通常对于Distinct Count来说，要设计通用的预聚合也不是一件容易的事）。因此，涉及到多对多维度的查询无法使用预聚合或者聚合缓存，除非直接命中才有效。不过在几种特殊情形下多对多关系还是有可能被预聚合的，详细信息参考：Analysis Services Many-to-Many Dimensions: Query Performance Optimization 技术白皮书。</li>
<li>因为多对多无法被预聚合，很多MDX计算例如VisualTotals，subselects和Create Subcube都会遇到问题。</li>
</ul>
<h3>数据精准性</h3>
<p>正如你在“数据精准性问题”这一节中看到的，在应用多对多关系的场景中你可能会得不到期望的值（例如重复计算）。所以，即便这是一项非常强大的功能，如果用户没有认识到背后的多对多关系，他可能会得到错误的结果。</p>
<h2>分析</h2>
<p>你可以参考Marco Russo写的<a title="Many-to-many维度建模" href="http://www.sqlbi.eu/Default.aspx?tabid=80" target="_blank">Many-to-many维度建模</a>，里头提及了很多基于多对多维度关系之上建模的解决方案。对于数据仓库以及商业智能问题来说，“是否应该使用多对多维度”这个问题，不存在一个绝对的答案。重要的是，你在实际应用之前，首先需要理解多对多背后的含义。</p>
<p>在 [Sales Reason]这个示例中，有多种情况可以判断是否应该使用多对多维度：</p>
<h3>你想要多对多关系，并且经常会使用Sales Reason维度去剖析数据。</h3>
<p>如果你经常需要使用Sales Reason维度去剖析数据，那么你其实并不需要一个中间度量组。在这个场景中，你可以将[FactInternetSales]和[FactInternetSalesReason]表合成一张新的事实表，然后基于这张表上建立新的数据立方体。因为你经常需要使用sales reason维度去剖析数据，当你使用[Price]成员去剖析数据的时候，以下高亮的行会被选中：</p>
<p><img style="display: inline; border: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image5.png" border="0" alt="image" width="546" height="81" /></p>
<p>如果你选择了[Other]成员来剖析的话，以下高亮的行会被选中：</p>
<p><img style="display: inline; border: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image6.png" border="0" alt="image" width="539" height="79" /></p>
<p>如果你想要获取汇总值，例如总销售额，你可以基于FactInternetSales表建立新的数据立方体，这样就不需要通过中间度量分组。</p>
<p><img style="display: inline; border: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image7.png" border="0" alt="image" width="303" height="68" /></p>
<h3>你实际上并不需要多对多关系</h3>
<p>在我们这个场景中，实际上根本并不需要多对多关系。想想看，事实上，我们只需要规定，每笔销售订单只允许有一个销售成功因素即可。</p>
<p><img style="display: inline; border: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image8.png" border="0" alt="image" width="464" height="34" /></p>
<p>或</p>
<p><img style="display: inline; border: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image9.png" border="0" alt="image" width="467" height="35" /></p>
<p>另外一种处理办法是将此订单的销售额分摊到不同的销售成功因素上。</p>
<p><img style="display: inline; border: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2010/04/image10.png" border="0" alt="image" width="486" height="51" /></p>
<h2>结论</h2>
<p>注意，以上说的这些并不是要告诉你，不要去使用多对多维度。这是一项非常棒的功能，它让用户能够实现他们想要的效果——将多个维度成员关联到同一个事实表记录上，同时在计算总和的时候又不会出现重复计算的问题。但需要注意，使用多对多维度对于汇总值的影响（例如，将所有单元格的值汇总起来并不总是等于实际的总值）还有它对于其他维度的影响。同时，还需要考虑性能方面的问题，虽然在<a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=3494E712-C90B-4A4E-AD45-01009C15C665&amp;displaylang=en">Analysis Services Many-to-Many Dimensions: Query Performance Optimization </a>技术白皮书中已经对如何优化多对多的查询性能做出了指导。在处理多对多问题上还有其他的解决方案，所以请确保你已经考虑过这些解决方案，并且已经理解了多对多的潜在问题。</p>
<p style="text-align: right;">——<a title="Analysis Services：你应该使用多对多维度吗？" href="http://www.imkevinyang.com/2010/04/Analysis%20Services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/analysis-services" title="Analysis Services" rel="tag">Analysis Services</a>, <a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/olap" title="OLAP" rel="tag">OLAP</a>, <a href="http://www.imkevinyang.com/tags/%e5%a4%9a%e5%af%b9%e5%a4%9a" title="多对多" rel="tag">多对多</a>, <a href="http://www.imkevinyang.com/tags/%e5%ba%a6%e9%87%8f%e7%bb%84" title="度量组" rel="tag">度量组</a>, <a href="http://www.imkevinyang.com/tags/%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96" title="性能优化" rel="tag">性能优化</a>, <a href="http://www.imkevinyang.com/tags/%e7%bb%b4%e5%ba%a6" title="维度" rel="tag">维度</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2010/05/64%e4%bd%8d%e7%b3%bb%e7%bb%9f%e4%b8%8biis7-isapi%e5%a4%84%e7%90%86%e5%99%a8%e5%8a%a0%e8%bd%bd%e5%a4%b1%e8%b4%a5.html" title="64位系统下IIS7 ISAPI处理器加载失败 (2010/05/05)">64位系统下IIS7 ISAPI处理器加载失败</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/analysis-service-2005-olap-best-practice-white-paper.html" title="Analysis Service 2005 OLAP Best Practice White Paper (2009/05/22)">Analysis Service 2005 OLAP Best Practice White Paper</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5.html" title="Analysis Services 2005 OLAP设计最佳实践 (2009/04/02)">Analysis Services 2005 OLAP设计最佳实践</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/bids%e5%af%b9%e4%ba%8e%e7%bb%b4%e5%ba%a6%e5%b1%9e%e6%80%a7%e9%94%ae%e4%b8%ba%e5%8f%af%e5%8f%98%e9%95%bf%e5%88%97%e6%97%b6%e5%ad%98%e5%9c%a8%e7%9a%84bug.html" title="BIDS对于维度属性键为可变长列时存在的Bug (2009/03/22)">BIDS对于维度属性键为可变长列时存在的Bug</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/bids%e9%83%a8%e7%bd%b2%e6%97%b6%e5%87%ba%e7%8e%b0%e5%85%83%e6%95%b0%e6%8d%ae%e7%ae%a1%e7%90%86%e5%99%a8%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af.html" title="BIDS部署时出现元数据管理器发生错误 (2009/03/13)">BIDS部署时出现元数据管理器发生错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/01/google-analytics%e4%b8%ad%e7%9a%84page%e7%bb%b4%e5%ba%a6.html" title="Google Analytics中的Page维度 (2010/01/04)">Google Analytics中的Page维度</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/olap%e4%b8%ad%e7%9a%84averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f.html" title="OLAP中的AverageOfChildren聚合方式 (2009/08/10)">OLAP中的AverageOfChildren聚合方式</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/07/ssas%e5%a4%84%e7%90%86%e6%97%b6%e6%89%be%e4%b8%8d%e5%88%b0%e5%b1%9e%e6%80%a7%e9%94%ae%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95.html" title="SSAS处理时&ldquo;找不到属性键&rdquo;的解决办法 (2010/07/19)">SSAS处理时&ldquo;找不到属性键&rdquo;的解决办法</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/10/%e5%85%a8%e5%8d%8a%e8%a7%92%e7%a9%ba%e6%a0%bc%e5%af%bc%e8%87%b4%e7%9a%84analysis-service%e5%a4%84%e7%90%86%e9%94%99%e8%af%af.html" title="全半角空格导致的Analysis Services处理错误 (2009/10/09)">全半角空格导致的Analysis Services处理错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/%e6%9d%83%e9%99%90%e5%af%bc%e8%87%b4%e7%9a%84analysis%e6%80%a7%e8%83%bd%e8%ae%a1%e6%95%b0%e5%99%a8%e5%9c%a8vistawin2008%e4%b8%8b%e5%a4%b1%e6%95%88%e7%9a%84%e9%97%ae%e9%a2%98.html" title="权限不足导致的Analysis性能计数器在Vista/win2008下失效的问题 (2009/11/12)">权限不足导致的Analysis性能计数器在Vista/win2008下失效的问题</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2010/04/analysis-services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>权限不足导致的Analysis性能计数器在Vista/win2008下失效的问题</title>
		<link>http://www.imkevinyang.com/2009/11/%e6%9d%83%e9%99%90%e5%af%bc%e8%87%b4%e7%9a%84analysis%e6%80%a7%e8%83%bd%e8%ae%a1%e6%95%b0%e5%99%a8%e5%9c%a8vistawin2008%e4%b8%8b%e5%a4%b1%e6%95%88%e7%9a%84%e9%97%ae%e9%a2%98.html</link>
		<comments>http://www.imkevinyang.com/2009/11/%e6%9d%83%e9%99%90%e5%af%bc%e8%87%b4%e7%9a%84analysis%e6%80%a7%e8%83%bd%e8%ae%a1%e6%95%b0%e5%99%a8%e5%9c%a8vistawin2008%e4%b8%8b%e5%a4%b1%e6%95%88%e7%9a%84%e9%97%ae%e9%a2%98.html#comments</comments>
		<pubDate>Wed, 11 Nov 2009 17:55:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[疑难杂症]]></category>
		<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[MSAS]]></category>
		<category><![CDATA[失效]]></category>
		<category><![CDATA[性能计数器]]></category>
		<category><![CDATA[权限]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/11/%e6%9d%83%e9%99%90%e5%af%bc%e8%87%b4%e7%9a%84analysis%e6%80%a7%e8%83%bd%e8%ae%a1%e6%95%b0%e5%99%a8%e5%9c%a8vistawin2008%e4%b8%8b%e5%a4%b1%e6%95%88%e7%9a%84%e9%97%ae%e9%a2%98.html</guid>
		<description><![CDATA[<p>这几个月一直在做Analysis Service相关的优化，包括Mdx的查询优化，以及处理的优化。微软发布的SSAS2008性能白皮书中推荐使用Profiler配合Analysis相关的性能计数器来监视各种性能指标。可是当我打开性能监视器，添加完相关计数器之后，无论做什么操作，包括查询、处理，性能指标&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>这几个月一直在做Analysis Service相关的优化，包括Mdx的查询优化，以及处理的优化。微软发布的SSAS2008性能白皮书中推荐使用Profiler配合Analysis相关的性能计数器来监视各种性能指标。可是当我打开性能监视器，添加完相关计数器之后，无论做什么操作，包括查询、处理，性能指标均是0，没有数据。</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/11/image_thumb11.png" width="291" height="181" /> </p>
<p>而Sql Server相关的性能计数器却是正常的，按理说，Analysis和Sql Server是一块安装的，要出问题应该是一起出问题才是。我有两台安装了windows server 2008（X64）的服务器均是如此。我自用的win7机器也是一样的问题。</p>
<p>在经过一个月的搜索、发帖询问后，我总算在<a title="Why is all my analysis performance counter(MSAS 2008) always show no data" href="http://social.msdn.microsoft.com/Forums/en-US/sqlanalysisservices/thread/d2655eaf-1abb-4c47-b72c-c894418514f3" target="_blank">MSDN论坛</a>上等到答案。Darren（这家伙相当热心，我好多莫名其妙的问题都是他解决或给的启发）说可能是权限问题，建议我把<strong><font color="#008000">Olap服务从network service帐户改成使用admin帐号启动</font></strong>，我测试了一下，这下果然指标全都正常了。</p>
<p>回想起安装Sql Server的时候，好像默认是会使用Network Service启动的。真搞不懂。既然是因为权限不足的原因，起码也给个提示呀。更让我不解的是，Sql Server的服务也是使用Network Service帐户启动的，但是性能计数器却工作正常。</p>
<p>为了找到真正出现权限问题的地方，我用尽了各种方法，包括给那些我认为相关的文件加上network service权限，重建计数器，注册表对比和跟踪，跟踪msmdctr100.dll（性能计数器相关的dll）的活动，检查Analysis相关日志，等等。最终除了发现一些乱七八糟不想关的信息之外，还是没能找到问题所在，只好放弃。</p>
<p>希望此文对那些和我一样遭遇类似问题的童鞋有帮助。</p>
<p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/analysis-services" title="Analysis Services" rel="tag">Analysis Services</a>, <a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/msas" title="MSAS" rel="tag">MSAS</a>, <a href="http://www.imkevinyang.com/tags/%e5%a4%b1%e6%95%88" title="失效" rel="tag">失效</a>, <a href="http://www.imkevinyang.com/tags/%e6%80%a7%e8%83%bd%e8%ae%a1%e6%95%b0%e5%99%a8" title="性能计数器" rel="tag">性能计数器</a>, <a href="http://www.imkevinyang.com/tags/%e6%9d%83%e9%99%90" title="权限" rel="tag">权限</a>, <a href="http://www.imkevinyang.com/categories/techarticles/knottyproblems" title="疑难杂症" rel="tag">疑难杂症</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2010/05/64%e4%bd%8d%e7%b3%bb%e7%bb%9f%e4%b8%8biis7-isapi%e5%a4%84%e7%90%86%e5%99%a8%e5%8a%a0%e8%bd%bd%e5%a4%b1%e8%b4%a5.html" title="64位系统下IIS7 ISAPI处理器加载失败 (2010/05/05)">64位系统下IIS7 ISAPI处理器加载失败</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5.html" title="Analysis Services 2005 OLAP设计最佳实践 (2009/04/02)">Analysis Services 2005 OLAP设计最佳实践</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/04/analysis-services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html" title="Analysis Services：你应该使用多对多维度吗？ (2010/04/12)">Analysis Services：你应该使用多对多维度吗？</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/bids%e9%83%a8%e7%bd%b2%e6%97%b6%e5%87%ba%e7%8e%b0%e5%85%83%e6%95%b0%e6%8d%ae%e7%ae%a1%e7%90%86%e5%99%a8%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af.html" title="BIDS部署时出现元数据管理器发生错误 (2009/03/13)">BIDS部署时出现元数据管理器发生错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/olap%e4%b8%ad%e7%9a%84averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f.html" title="OLAP中的AverageOfChildren聚合方式 (2009/08/10)">OLAP中的AverageOfChildren聚合方式</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/07/ssas%e5%a4%84%e7%90%86%e6%97%b6%e6%89%be%e4%b8%8d%e5%88%b0%e5%b1%9e%e6%80%a7%e9%94%ae%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95.html" title="SSAS处理时&ldquo;找不到属性键&rdquo;的解决办法 (2010/07/19)">SSAS处理时&ldquo;找不到属性键&rdquo;的解决办法</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/12/win7vista%e9%ab%98%e7%ba%a7%e7%94%a8%e6%88%b7%e5%bf%85%e5%a4%87%e7%9a%84%e5%8f%b3%e9%94%ae%e8%8f%9c%e5%8d%95take-back-my-ownership.html" title="Win7/Vista高级用户必备的右键菜单Take back my Ownership! (2009/12/06)">Win7/Vista高级用户必备的右键菜单Take back my Ownership!</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/10/%e5%85%a8%e5%8d%8a%e8%a7%92%e7%a9%ba%e6%a0%bc%e5%af%bc%e8%87%b4%e7%9a%84analysis-service%e5%a4%84%e7%90%86%e9%94%99%e8%af%af.html" title="全半角空格导致的Analysis Services处理错误 (2009/10/09)">全半角空格导致的Analysis Services处理错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2011/05/%e8%a7%a3%e5%86%b3%e6%96%b0%e5%88%9b%e5%bb%ba%e7%9a%84windows%e7%94%a8%e6%88%b7%e6%97%a0%e6%b3%95%e8%ae%bf%e9%97%aetfs%e7%9a%84%e9%97%ae%e9%a2%98.html" title="解决新创建的windows用户无法访问TFS的问题 (2011/05/12)">解决新创建的windows用户无法访问TFS的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3%e7%bb%b4%e5%ba%a6%e6%88%90%e5%91%98%e4%b8%ad%e7%9a%84%e9%9d%9e%e6%b3%95xml%e5%ad%97%e7%ac%a6%e5%af%bc%e8%87%b4%e7%9a%84%e6%9f%a5%e8%af%a2%e9%94%99%e8%af%af-2.html" title="解决维度成员中的非法Xml字符导致的查询错误 (2009/09/19)">解决维度成员中的非法Xml字符导致的查询错误</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/11/%e6%9d%83%e9%99%90%e5%af%bc%e8%87%b4%e7%9a%84analysis%e6%80%a7%e8%83%bd%e8%ae%a1%e6%95%b0%e5%99%a8%e5%9c%a8vistawin2008%e4%b8%8b%e5%a4%b1%e6%95%88%e7%9a%84%e9%97%ae%e9%a2%98.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>全半角空格导致的Analysis Services处理错误</title>
		<link>http://www.imkevinyang.com/2009/10/%e5%85%a8%e5%8d%8a%e8%a7%92%e7%a9%ba%e6%a0%bc%e5%af%bc%e8%87%b4%e7%9a%84analysis-service%e5%a4%84%e7%90%86%e9%94%99%e8%af%af.html</link>
		<comments>http://www.imkevinyang.com/2009/10/%e5%85%a8%e5%8d%8a%e8%a7%92%e7%a9%ba%e6%a0%bc%e5%af%bc%e8%87%b4%e7%9a%84analysis-service%e5%a4%84%e7%90%86%e9%94%99%e8%af%af.html#comments</comments>
		<pubDate>Fri, 09 Oct 2009 13:48:52 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Key not found]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[全半角]]></category>
		<category><![CDATA[处理异常]]></category>
		<category><![CDATA[属性未找到]]></category>
		<category><![CDATA[排序规则]]></category>
		<category><![CDATA[空格]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/10/%e5%85%a8%e5%8d%8a%e8%a7%92%e7%a9%ba%e6%a0%bc%e5%af%bc%e8%87%b4%e7%9a%84analysis-service%e5%a4%84%e7%90%86%e9%94%99%e8%af%af.html</guid>
		<description><![CDATA[问题描述
<p>某维度表的字符串列同时出现两条记录，A记录以半角空格（英文空格）结束，B记录以全角空格（中文空格）结束，除此之外其他部分均相同。Analysis Service处理的时候抛出“Key not found”的异常，导致处理失败。</p>
<p>为了实验，我们创建两张非常简单的表：</p>
<pre class="csharpcode"><span class="rem">-- 员工交易事实表</span>
<span class="kwrd">Create</span> <span class="kwrd">Tab&#8230;</span></pre>]]></description>
			<content:encoded><![CDATA[<h2>问题描述</h2>
<p>某维度表的字符串列同时出现两条记录，A记录以半角空格（英文空格）结束，B记录以全角空格（中文空格）结束，除此之外其他部分均相同。Analysis Service处理的时候抛出“Key not found”的异常，导致处理失败。</p>
<p>为了实验，我们创建两张非常简单的表：</p>
<pre class="csharpcode"><span class="rem">-- 员工交易事实表</span>
<span class="kwrd">Create</span> <span class="kwrd">Table</span> [FactTransaction](
    [TransactionKey] [<span class="kwrd">int</span>] <span class="kwrd">not</span> <span class="kwrd">null</span>,
    [EmployeeKey] [<span class="kwrd">int</span>] <span class="kwrd">not</span> <span class="kwrd">null</span>
)
<span class="rem">-- 员工维度表</span>
<span class="kwrd">Create</span> <span class="kwrd">Table</span> [DimEmployee](
    [EmployeeKey] [<span class="kwrd">int</span>]<span class="kwrd">not</span> <span class="kwrd">null</span>,
    [EmployeeName] [nvarchar](32) <span class="kwrd">not</span> <span class="kwrd">null</span>
)</pre>
<p>接着我们开始往维度表中添加几条记录。</p>
<pre class="csharpcode">insert <span class="kwrd">into</span> DimEmployee(EmployeeKey,EmployeeName)<span class="kwrd">values</span>(1,<span class="str">'员工 '</span>)    <span class="rem">-- 半角空格</span>
insert <span class="kwrd">into</span> DimEmployee(EmployeeKey,EmployeeName)<span class="kwrd">values</span>(2,<span class="str">'员工　'</span>)    -- 全角空格</pre>
<p>然后我们在BIDS中新建一个Analysis Service的Olap工程，将DimEmployee表作为维度表，并新建指标TotalTransactions ::= Count(TransactionKey)表示每个员工的交易数量：</p>
<p><img style="display: inline; border-width: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/10/image_thumb8.png" border="0" alt="image" width="129" height="58" /></p>
<p>所有设置保持默认，OK，现在开始处理Employee维度。这个时候Analysis Service会提示你：</p>
<blockquote><p>Processing Dimension Attribute 'EmployeeKey' failed. 1 rows have been read.</p>
<p>OLAP 存储引擎中存在错误: 处理时找不到以下属性键: 表:“dbo_DimEmployee”，列:“EmployeeName”，值:“员工 ”。该属性为“EmployeeName”。</p></blockquote>
<p>这个错误翻译成英文就是Key not found.</p>
<p><img style="display: inline; border-width: 0px;" title="处理时找不到以下属性键(Key not found)" src="http://www.imkevinyang.com/wp-content/uploads/2009/10/image_thumb9.png" border="0" alt="处理时找不到以下属性键(Key not found)" width="410" height="124" /></p>
<h2>问题分析</h2>
<h3>发生了什么事</h3>
<p>在我们上面设计的OLAP方案中，一个EmployeeKey有且只能有一个EmployeeName，EmployeeKey属性的处理依赖于EmployeeName属性。这个依赖关系在维度设计视图中的Attribute Relationship属性关系面板中指定。</p>
<p><img style="display: inline; border-width: 0px;" title="Attribute Relationship" src="http://www.imkevinyang.com/wp-content/uploads/2009/10/image_thumb10.png" border="0" alt="Attribute Relationship" width="244" height="124" /></p>
<p>Analysis Service会在处理完EmployeeName属性之后再处理EmployeeKey属性。在处理每一个EmployeeKey属性成员的时候，都会去找对应的EmployeeName属性成员。</p>
<p>上面的处理错误实际上就是说，在处理EmployeeKey的某个成员的时候，它对应的EmployeeName属性成员应该是“员工 ”（全角空格）的——从表记录中可以看到这个对应关系——但是在属性存储文件（Analysis Service自己的存储结构）中却找不到该属性成员。</p>
<p>这里没有告诉我们到底是哪个EmployeeKey属性成员处理的时候出了问题，但是由于我们的数据仓库非常简单，我们可以直接看出来，EmployeeName=“员工 ”（全角空格）的EmployeeKey为2。</p>
<p>那为什么全角空格的EmployeeName属性成员没有导入到Analysis Service的属性存储文件中呢？我们来展开看一下处理EmployeeName时Analysis Service向Sql Server发起的查询。</p>
<pre class="csharpcode"><span class="kwrd">SELECT</span>
  <span class="kwrd">DISTINCT</span>
 [dbo_DimEmployee].[EmployeeName] <span class="kwrd">AS</span> [dbo_DimEmployeeEmployeeName0_0]
  <span class="kwrd">FROM</span> [dbo].[DimEmployee] <span class="kwrd">AS</span> [dbo_DimEmployee]</pre>
<p>将这行代码放到Sql Server中去执行一下，<strong><span style="color: #008000;">我们发现sql Server只给我们返回了半角空格的记录，全角空格的记录被过滤掉了。这也就解释了，为什么全角空格的属性成员没能进入Analysis service中。进而导致依赖这个成员的属性处理失败</span></strong>。</p>
<h3>Sql Server Collation</h3>
<p>这里需要提一下Sql Server的排序规则（Collation）。排序规则会<img style="margin: 5px 0px 0px 5px; display: inline; border-width: 0px;" title="Sql Server Collation" src="http://www.imkevinyang.com/wp-content/uploads/2009/10/image_thumb11.png" border="0" alt="Sql Server Collation" width="244" height="189" align="right" />影响数据之间的比较以及顺序。具体细节参见MSDN：<a title="SQL Server Collation Fundamentals" href="Fundamentalshttp://msdn.microsoft.com/en-us/library/aa174903%28SQL.80%29.aspx" target="_blank">SQL Server Collation Fundamentals</a> 。这里我只提一个和这个问题相关的，并且容易被人遗忘的设置，那就是Width-Sensitive（宽度敏感）设置。我们知道，有些字符既有单字节形式（半角字符），又有双字节形式（全角字符），例如1234和１２３４。如果设置为宽度不敏感，那么Sql Server就会将这些字符的单双字节形式一视同仁。这样你在select distinct的时候，单双字节字符形式的字符串就只能一个。这也就是为什么上面我们select distinct的时候只出来半角空格的缘故。</p>
<h3>Sql Server和Analysis Service排序规则相同为什么还会出错？</h3>
<p>Analysis Service自己也有一个排序规则的设置。我们检查了一下这两者的设置，发现是一样的。那么Analysis Service在查找“员工 ”（全角空格）属性成员的时候，即使找不到这个成员，但是应该至少可以匹配到“员工 ”（半角空格）的成员才是呀。<strong><span style="color: #008000;">关键是，半角空格的成员也根本不存在。默认情况下，所有字符串类型的维度属性在处理时都会被right trim，也就是结尾的空格均会被去除。</span></strong></p>
<p><img style="display: inline; border-width: 0px;" title="维度属性面板Trimming" src="http://www.imkevinyang.com/wp-content/uploads/2009/10/image_thumb12.png" border="0" alt="维度属性面板Trimming" width="244" height="192" /></p>
<p>也就是说，最终进入Analysis Service的属性成员是“员工”，不带任何空格，而这个成员和全角空格（<strong><span style="color: #008000;">全角空格无法被right trimming掉</span></strong>）的显然无法匹配上。</p>
<h3>发散一下</h3>
<p>如果Analysis设置了对每个属性成员左右都trim的话，那么一旦数据仓库出现“ 员工”（左边带全角空格）和“ 员工”（左边带半角空格）的数据的时候，处理失败。</p>
<p>如果数据仓库中同时出现“员工”，“员工 ”（全角空格），那么也会造成出错，这是因为select distinct会将右侧空格去除之后再比较数据是否相等。</p>
<p>如果将维度属性的Trimming设置为None的话，那么当数据仓库中出现“员工”，“员工   ”（若干个半角空格结尾）这样数据的时候，也会造成处理失败，这也是为什么Analysis Service默认设置为right trimming的其中一个原因（和Sql Server的行为保持一致）。</p>
<p>如果数据中同时出现“员工 ”（半角空格），“员工 ”（全角空格），“员工 ”（先全角空格，再tab空格）这样的数据组合，处理正常。</p>
<h2>总结</h2>
<p>出现这样的情况，不好通过改变Sql Server或者Analysis Service的排序规则来修正这个问题。只能在ETL的阶段对此类数据进行预处理，将末尾的全角空格给剔除掉。如果业务系统对全半角的区别不感兴趣，也可以直接使用正则表达式将所有全角字符替换成相应的半角字符。</p>
<p style="text-align: right;">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/analysis-services" title="Analysis Services" rel="tag">Analysis Services</a>, <a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/key-not-found" title="Key not found" rel="tag">Key not found</a>, <a href="http://www.imkevinyang.com/tags/sql-server" title="SQL Server" rel="tag">SQL Server</a>, <a href="http://www.imkevinyang.com/tags/%e5%85%a8%e5%8d%8a%e8%a7%92" title="全半角" rel="tag">全半角</a>, <a href="http://www.imkevinyang.com/tags/%e5%a4%84%e7%90%86%e5%bc%82%e5%b8%b8" title="处理异常" rel="tag">处理异常</a>, <a href="http://www.imkevinyang.com/tags/%e5%b1%9e%e6%80%a7%e6%9c%aa%e6%89%be%e5%88%b0" title="属性未找到" rel="tag">属性未找到</a>, <a href="http://www.imkevinyang.com/tags/%e6%8e%92%e5%ba%8f%e8%a7%84%e5%88%99" title="排序规则" rel="tag">排序规则</a>, <a href="http://www.imkevinyang.com/tags/%e7%a9%ba%e6%a0%bc" title="空格" rel="tag">空格</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2010/05/64%e4%bd%8d%e7%b3%bb%e7%bb%9f%e4%b8%8biis7-isapi%e5%a4%84%e7%90%86%e5%99%a8%e5%8a%a0%e8%bd%bd%e5%a4%b1%e8%b4%a5.html" title="64位系统下IIS7 ISAPI处理器加载失败 (2010/05/05)">64位系统下IIS7 ISAPI处理器加载失败</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5.html" title="Analysis Services 2005 OLAP设计最佳实践 (2009/04/02)">Analysis Services 2005 OLAP设计最佳实践</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/04/analysis-services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html" title="Analysis Services：你应该使用多对多维度吗？ (2010/04/12)">Analysis Services：你应该使用多对多维度吗？</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/bids%e9%83%a8%e7%bd%b2%e6%97%b6%e5%87%ba%e7%8e%b0%e5%85%83%e6%95%b0%e6%8d%ae%e7%ae%a1%e7%90%86%e5%99%a8%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af.html" title="BIDS部署时出现元数据管理器发生错误 (2009/03/13)">BIDS部署时出现元数据管理器发生错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/olap%e4%b8%ad%e7%9a%84averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f.html" title="OLAP中的AverageOfChildren聚合方式 (2009/08/10)">OLAP中的AverageOfChildren聚合方式</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/sql-server%e4%b8%ad%e4%bf%ae%e6%94%b9%e8%87%aa%e5%a2%9e%e9%95%bf%e5%88%97%e7%bb%8f%e5%b8%b8%e9%9c%80%e8%a6%81%e7%94%a8%e5%88%b0%e7%9a%84%e9%85%8d%e7%bd%ae.html" title="Sql Server中修改自增长列经常需要用到的配置 (2009/05/24)">Sql Server中修改自增长列经常需要用到的配置</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/08/sql-server%e9%87%8d%e5%91%bd%e5%90%8d%e6%89%80%e6%9c%89%e5%a4%96%e9%94%ae%e7%ba%a6%e6%9d%9f.html" title="Sql Server重命名所有外键约束 (2010/08/02)">Sql Server重命名所有外键约束</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/07/ssas%e5%a4%84%e7%90%86%e6%97%b6%e6%89%be%e4%b8%8d%e5%88%b0%e5%b1%9e%e6%80%a7%e9%94%ae%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95.html" title="SSAS处理时&ldquo;找不到属性键&rdquo;的解决办法 (2010/07/19)">SSAS处理时&ldquo;找不到属性键&rdquo;的解决办法</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/05/ssis%e8%b0%83%e7%94%a8%e5%ad%98%e5%82%a8%e8%bf%87%e7%a8%8b%e5%a4%b1%e8%b4%a5.html" title="SSIS调用存储过程失败 (2010/05/23)">SSIS调用存储过程失败</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/07/visual-studio%e7%bc%96%e8%be%91%e5%99%a8%e4%b8%80%e6%ac%a1%e7%bc%a9%e8%bf%9b%e5%8f%8d%e7%bc%a9%e8%bf%9b4%e4%b8%aa%e7%a9%ba%e6%a0%bc.html" title="Visual Studio编辑器一次缩进/反缩进4个空格 (2010/07/04)">Visual Studio编辑器一次缩进/反缩进4个空格</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/10/%e5%85%a8%e5%8d%8a%e8%a7%92%e7%a9%ba%e6%a0%bc%e5%af%bc%e8%87%b4%e7%9a%84analysis-service%e5%a4%84%e7%90%86%e9%94%99%e8%af%af.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>解决维度成员中的非法Xml字符导致的查询错误</title>
		<link>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3%e7%bb%b4%e5%ba%a6%e6%88%90%e5%91%98%e4%b8%ad%e7%9a%84%e9%9d%9e%e6%b3%95xml%e5%ad%97%e7%ac%a6%e5%af%bc%e8%87%b4%e7%9a%84%e6%9f%a5%e8%af%a2%e9%94%99%e8%af%af-2.html</link>
		<comments>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3%e7%bb%b4%e5%ba%a6%e6%88%90%e5%91%98%e4%b8%ad%e7%9a%84%e9%9d%9e%e6%b3%95xml%e5%ad%97%e7%ac%a6%e5%af%bc%e8%87%b4%e7%9a%84%e6%9f%a5%e8%af%a2%e9%94%99%e8%af%af-2.html#comments</comments>
		<pubDate>Sat, 19 Sep 2009 15:29:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Mdx]]></category>
		<category><![CDATA[异常]]></category>
		<category><![CDATA[维度]]></category>
		<category><![CDATA[非法Xml字符]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/10/%e8%a7%a3%e5%86%b3%e7%bb%b4%e5%ba%a6%e6%88%90%e5%91%98%e4%b8%ad%e7%9a%84%e9%9d%9e%e6%b3%95xml%e5%ad%97%e7%ac%a6%e5%af%bc%e8%87%b4%e7%9a%84%e6%9f%a5%e8%af%a2%e9%94%99%e8%af%af-2.html</guid>
		<description><![CDATA[<p><font color="#ff0000">update(2009-09-20): 增加了去除这些非法Xml字符的正则表达式以及C#代码。</font></p>
问题描述
<p>最近在项目中遇到这么个情况，在展开维度成员的时候，服务端抛出了“The server sent an unrecognizable response”的异常，看了下异常细节，给出的信息是“'', hexadeci&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p><font color="#ff0000">update(2009-09-20): 增加了去除这些非法Xml字符的正则表达式以及C#代码。</font></p>
<h2>问题描述</h2>
<p>最近在项目中遇到这么个情况，在展开维度成员的时候，服务端抛出了“The server sent an unrecognizable response”的异常，看了下异常细节，给出的信息是“'', hexadecimal value 0x01, is an invalid character. Line 1, position 6771. (System.Xml) ”。</p>
<h2>问题解决</h2>
<p>出现这样问题的原因在于，微软的Analysis Service使用XMLA（XML for Analysis）语言和其他客户端进行交互，包括执行Mdx、DMX、Sql等。<strong><font color="#008000">如果服务端返回的成员（关键列、名字、标题、成员值等）含有一些非打印字符的话，那么就无法直接在Xml中表示，这样就会导致客户端无法解析返回的Xml响应，而出现上述的错误</font></strong>。</p>
<p>Analysis Service在Process的时候，出于性能考虑默认情况下是不会对数据进行这种Xml非法字符的检测。不过Analysis Service也提供了一个设置开关，允许我们在处理阶段检测这些非法字符，并做一定的规范化处理。在BIDS中，我们打开维度属性的属性面板，有一个InvalidXmlCharacters的设置，如下图所示：</p>
<p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="InvalidXmlCharacters设置" border="0" alt="InvalidXmlCharacters设置" src="http://www.imkevinyang.com/wp-content/uploads/2009/10/image_thumb.png" width="218" height="168" /> </p>
<p><strong><font color="#008000">默认情况下其值为Preserve，也就是保留这些非法字符。它还有其他两个选项。Remove表示移除这些非法字符，只保留合法的Xml字符。Replace表示使用问号?替换非法字符，一个非法字符对应一个问号</font></strong>。在实际应用中，InvalidXmlCharacters需要根据项目的实际情况进行设置。如果对数据的这种清理可以放到ETL阶段，那么最好放到ETL阶段，因为这样可以加快Analysis Service处理的速度。否则就只能在Process的时候做检测了。对于Remove和Replace，我比较倾向于选择Remove。因为既然已经是非打印字符了，用问号代替固然能够和其他数据区分开来，但是对于最终用户来说，大部分情况下只会增加他们的迷惑而已。</p>
<h2>剔除非法Xml字符</h2>
<p>在<a title="Xml 1.0规范" href="http://www.w3.org/TR/REC-xml/#NT-Char" target="_blank">Xml 1.0规范</a>（第五版，06/11/2008）的2.2一节中提到了Xml合法字符的范围：</p>
<blockquote><p><i>/* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */</i></p>
<p><code>Char</code> ::=&#160;&#160; <code>#x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]</code>       </p>
</blockquote>
<p>规范中建议，所有Xml处理器都应该正确处理上述范围的这些字符。</p>
<p>我们可以在处理字符串的时候使用正则表达式剔除掉非法的Xml字符，以保证最终进入Analysis Service的字符都是Xml合法字符。</p>
<pre class="csharpcode">[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]</pre>
<p>对应的C#代码如下，出于性能考虑，可以将函数内部的正则表达式存储为成员变量，并设置为预编译模式。</p>
<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">static</span> String StripInvalidXmlChars(String input)
{
  Regex re = <span class="kwrd">new</span> Regex(<span class="str">@&quot;[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]&quot;</span>);
  <span class="kwrd">return</span> re.Replace(input, <span class="str">&quot;&quot;</span>);
}</pre>
<p>&#160;</p>
<p>参考文档：</p>
<p><a href="http://cse-mjmcl.cse.bris.ac.uk/blog/2007/02/14/1171465494443.html" rel="nofollow">Invalid XML Characters: when valid UTF8 does not mean valid XML</a></p>
<p><a title="unprintable characters in member names cause error" href="http://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=264939" rel="nofollow" target="_blank">unprintable characters in member names cause error</a></p>
<p><a title="Xml 1.0规范" href="http://www.w3.org/TR/REC-xml/#NT-Char" target="_blank">Xml 1.0规范</a></p>
<p align="right">——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/analysis-services" title="Analysis Services" rel="tag">Analysis Services</a>, <a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/mdx" title="Mdx" rel="tag">Mdx</a>, <a href="http://www.imkevinyang.com/tags/%e5%bc%82%e5%b8%b8" title="异常" rel="tag">异常</a>, <a href="http://www.imkevinyang.com/tags/%e7%bb%b4%e5%ba%a6" title="维度" rel="tag">维度</a>, <a href="http://www.imkevinyang.com/tags/%e9%9d%9e%e6%b3%95xml%e5%ad%97%e7%ac%a6" title="非法Xml字符" rel="tag">非法Xml字符</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2010/05/64%e4%bd%8d%e7%b3%bb%e7%bb%9f%e4%b8%8biis7-isapi%e5%a4%84%e7%90%86%e5%99%a8%e5%8a%a0%e8%bd%bd%e5%a4%b1%e8%b4%a5.html" title="64位系统下IIS7 ISAPI处理器加载失败 (2010/05/05)">64位系统下IIS7 ISAPI处理器加载失败</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5.html" title="Analysis Services 2005 OLAP设计最佳实践 (2009/04/02)">Analysis Services 2005 OLAP设计最佳实践</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/04/analysis-services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html" title="Analysis Services：你应该使用多对多维度吗？ (2010/04/12)">Analysis Services：你应该使用多对多维度吗？</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/bids%e5%af%b9%e4%ba%8e%e7%bb%b4%e5%ba%a6%e5%b1%9e%e6%80%a7%e9%94%ae%e4%b8%ba%e5%8f%af%e5%8f%98%e9%95%bf%e5%88%97%e6%97%b6%e5%ad%98%e5%9c%a8%e7%9a%84bug.html" title="BIDS对于维度属性键为可变长列时存在的Bug (2009/03/22)">BIDS对于维度属性键为可变长列时存在的Bug</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/bids%e9%83%a8%e7%bd%b2%e6%97%b6%e5%87%ba%e7%8e%b0%e5%85%83%e6%95%b0%e6%8d%ae%e7%ae%a1%e7%90%86%e5%99%a8%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af.html" title="BIDS部署时出现元数据管理器发生错误 (2009/03/13)">BIDS部署时出现元数据管理器发生错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/01/google-analytics%e4%b8%ad%e7%9a%84page%e7%bb%b4%e5%ba%a6.html" title="Google Analytics中的Page维度 (2010/01/04)">Google Analytics中的Page维度</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/javascript%e4%b8%ad%e8%8e%b7%e5%8f%96%e5%87%ba%e9%94%99%e4%bb%a3%e7%a0%81%e6%89%80%e5%9c%a8%e6%96%87%e4%bb%b6%e5%8f%8a%e8%a1%8c%e6%95%b0.html" title="Javascript中获取出错代码所在文件及行数 (2009/05/18)">Javascript中获取出错代码所在文件及行数</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/olap%e4%b8%ad%e7%9a%84averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f.html" title="OLAP中的AverageOfChildren聚合方式 (2009/08/10)">OLAP中的AverageOfChildren聚合方式</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/07/ssas%e5%a4%84%e7%90%86%e6%97%b6%e6%89%be%e4%b8%8d%e5%88%b0%e5%b1%9e%e6%80%a7%e9%94%ae%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95.html" title="SSAS处理时&ldquo;找不到属性键&rdquo;的解决办法 (2010/07/19)">SSAS处理时&ldquo;找不到属性键&rdquo;的解决办法</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/visual-studio%e5%b0%8f%e8%b4%b4%e5%a3%ab%e5%8a%a0%e4%ba%86try-catch%e4%b9%9f%e8%83%bd%e8%87%aa%e5%8a%a8%e5%ae%9a%e4%bd%8d%e5%88%b0%e5%bc%82%e5%b8%b8%e4%bb%a3%e7%a0%81.html" title="Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码 (2009/09/18)">Visual Studio小贴士&mdash;&mdash;加了Try-Catch也能自动定位到异常代码</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3%e7%bb%b4%e5%ba%a6%e6%88%90%e5%91%98%e4%b8%ad%e7%9a%84%e9%9d%9e%e6%b3%95xml%e5%ad%97%e7%ac%a6%e5%af%bc%e8%87%b4%e7%9a%84%e6%9f%a5%e8%af%a2%e9%94%99%e8%af%af-2.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>OLAP中的AverageOfChildren聚合方式</title>
		<link>http://www.imkevinyang.com/2009/08/olap%e4%b8%ad%e7%9a%84averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f.html</link>
		<comments>http://www.imkevinyang.com/2009/08/olap%e4%b8%ad%e7%9a%84averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f.html#comments</comments>
		<pubDate>Mon, 10 Aug 2009 15:52:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[AverageOfChildren聚合方式]]></category>
		<category><![CDATA[BI]]></category>
		<category><![CDATA[OLAP]]></category>
		<category><![CDATA[平均值]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/08/olap%e4%b8%ad%e7%9a%84averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f.html</guid>
		<description><![CDATA[<p>BI项目中，我们经常需要设计“平均值”这样的指标，例如电子商务中的平均销售额，Web分析中的平均访问时长，等等。而Analysis Service中提供了一个“AverageOfChildren”的聚合方式，看上去好像就是为了这样的需求而设计的。</p>
<p>但是测试结果却发现，得到的数据根本就不是我们期望的。后来&#8230;</p>]]></description>
			<content:encoded><![CDATA[<p>BI项目中，我们经常需要设计“平均值”这样的指标，例如电子商务中的平均销售额，Web分析中的平均访问时长，等等。而Analysis Service中提供了一个“AverageOfChildren”的聚合方式，看上去好像就是为了这样的需求而设计的。</p>
<p>但是测试结果却发现，得到的数据根本就不是我们期望的。后来查资料找到了关于这个聚合方式的说明：</p>
<blockquote><p>AverageOfChildren——对某个成员的聚合值等于其所有子成员的平均值。</p></blockquote>
<p>这是什么意思呢？假设我定义了一个“总销售额”和“平均销售额”这两个指标。当我看中国的数据的时候，假设中国的总销售额是34000万的话，因为中国下面有34个省级行政区（34个Member），因此平均销售额就是1000万。这是按照字面上的理解。但实际上，这样理解是错误的。MSDN上给出的解释并没有明确指明，<strong><span style="color: #008000;">AverageOfChildren这个聚合方式只是针对时间维度起作用</span></strong>。</p>
<p>在Analysis Service中内置了很多常见的维度类型，如时间维度，地理纬度，帐户维度等。你可以将你创建的维度的“类型”属性标记为内置的维度类型。这样的好处是，Analysis Service对这些标记为特殊类型的维度有额外的支持。例如如果你的Cube中包含一个标记为“时间维度”类型的维度时，那么你就可以在Mdx中使用和时间相关的函数，如Ytd等。类似的，AverageOfChildren这个聚合类型也是需要时间维度的支持，你首先需要在工程中显式指定至少一个时间维度。这个聚合方式的意义就是对所有的时间——以天为单位——求平均值。例如当前时间维度选择的成员是[2003年]，而03年有销售额数据的共有365天，那么</p>
<p><strong><span style="color: #008000;">AverageOfChildren(销售额） =  总销售额 / 365</span></strong></p>
<p>如果范围再进一步缩小，选择[2003年3月份]，由于3月份每天都有销售额，因此AverageOfChildren就等于总销售额除以31。你可以按具体日期去查看，你会发现，每天的总销售额和平均销售额是一样的。这是因为具体日期的粒度已经是最小的了。</p>
<p><img style="margin: 0px; display: inline; border-width: 0px;" title="image" src="http://www.imkevinyang.com/wp-content/uploads/2009/08/image_thumb8.png" border="0" alt="image" width="334" height="400" /></p>
<p>由于这个AverageOfChildren聚合方式只是针对时间维度的，不能满足大量的应用场景，因此通常我们都需要自己定义这样一个求平均值的计算指标。公式很简单：</p>
<p>平均值=总值 / 维度成员个数</p>
<p>例如我们想看月利润平均值，那么首先我们定义一个“总利润”的指标，那么</p>
<p>月利润平均值 = 总利润 / Count([Time].[CalendarMonth].children)</p>
<p><span style="color: #ff0000;">(update: 在Analysis Services 2008下，似乎这个聚合方式已经变成了对小时求平均，而不是以天作为最小单位。反正不管怎么样，这个聚合方式实在没什么太大作用)</span></p>
<p>——<a href="http://www.imkevinyang.com/"><em><strong>Kevin Yang</strong></em></a></p>

	标签：<a href="http://www.imkevinyang.com/tags/analysis-services" title="Analysis Services" rel="tag">Analysis Services</a>, <a href="http://www.imkevinyang.com/tags/averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f" title="AverageOfChildren聚合方式" rel="tag">AverageOfChildren聚合方式</a>, <a href="http://www.imkevinyang.com/tags/bi" title="BI" rel="tag">BI</a>, <a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/olap" title="OLAP" rel="tag">OLAP</a>, <a href="http://www.imkevinyang.com/tags/%e5%b9%b3%e5%9d%87%e5%80%bc" title="平均值" rel="tag">平均值</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2010/05/64%e4%bd%8d%e7%b3%bb%e7%bb%9f%e4%b8%8biis7-isapi%e5%a4%84%e7%90%86%e5%99%a8%e5%8a%a0%e8%bd%bd%e5%a4%b1%e8%b4%a5.html" title="64位系统下IIS7 ISAPI处理器加载失败 (2010/05/05)">64位系统下IIS7 ISAPI处理器加载失败</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/05/analysis-service-2005-olap-best-practice-white-paper.html" title="Analysis Service 2005 OLAP Best Practice White Paper (2009/05/22)">Analysis Service 2005 OLAP Best Practice White Paper</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/04/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5.html" title="Analysis Services 2005 OLAP设计最佳实践 (2009/04/02)">Analysis Services 2005 OLAP设计最佳实践</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/04/analysis-services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html" title="Analysis Services：你应该使用多对多维度吗？ (2010/04/12)">Analysis Services：你应该使用多对多维度吗？</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/bids%e9%83%a8%e7%bd%b2%e6%97%b6%e5%87%ba%e7%8e%b0%e5%85%83%e6%95%b0%e6%8d%ae%e7%ae%a1%e7%90%86%e5%99%a8%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af.html" title="BIDS部署时出现元数据管理器发生错误 (2009/03/13)">BIDS部署时出现元数据管理器发生错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/07/ssas%e5%a4%84%e7%90%86%e6%97%b6%e6%89%be%e4%b8%8d%e5%88%b0%e5%b1%9e%e6%80%a7%e9%94%ae%e7%9a%84%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95.html" title="SSAS处理时&ldquo;找不到属性键&rdquo;的解决办法 (2010/07/19)">SSAS处理时&ldquo;找不到属性键&rdquo;的解决办法</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/10/%e5%85%a8%e5%8d%8a%e8%a7%92%e7%a9%ba%e6%a0%bc%e5%af%bc%e8%87%b4%e7%9a%84analysis-service%e5%a4%84%e7%90%86%e9%94%99%e8%af%af.html" title="全半角空格导致的Analysis Services处理错误 (2009/10/09)">全半角空格导致的Analysis Services处理错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/11/%e6%9d%83%e9%99%90%e5%af%bc%e8%87%b4%e7%9a%84analysis%e6%80%a7%e8%83%bd%e8%ae%a1%e6%95%b0%e5%99%a8%e5%9c%a8vistawin2008%e4%b8%8b%e5%a4%b1%e6%95%88%e7%9a%84%e9%97%ae%e9%a2%98.html" title="权限不足导致的Analysis性能计数器在Vista/win2008下失效的问题 (2009/11/12)">权限不足导致的Analysis性能计数器在Vista/win2008下失效的问题</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/09/%e8%a7%a3%e5%86%b3%e7%bb%b4%e5%ba%a6%e6%88%90%e5%91%98%e4%b8%ad%e7%9a%84%e9%9d%9e%e6%b3%95xml%e5%ad%97%e7%ac%a6%e5%af%bc%e8%87%b4%e7%9a%84%e6%9f%a5%e8%af%a2%e9%94%99%e8%af%af-2.html" title="解决维度成员中的非法Xml字符导致的查询错误 (2009/09/19)">解决维度成员中的非法Xml字符导致的查询错误</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/08/olap%e4%b8%ad%e7%9a%84averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Analysis Services 2005 OLAP设计最佳实践白皮书（中文）</title>
		<link>http://www.imkevinyang.com/2009/07/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5-2.html</link>
		<comments>http://www.imkevinyang.com/2009/07/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5-2.html#comments</comments>
		<pubDate>Fri, 24 Jul 2009 01:17:00 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[技术随笔]]></category>
		<category><![CDATA[Analysis Service最佳实践中文]]></category>
		<category><![CDATA[Business Intelligence]]></category>
		<category><![CDATA[OLAP性能指南]]></category>
		<category><![CDATA[商业智能]]></category>
		<category><![CDATA[翻译]]></category>
		<category><![CDATA[设计]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/07/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5-2.html</guid>
		<description><![CDATA[<p><font color="#ff8040">英文原文：<a href="http://www.imkevinyang.com/2009/05/analysis-service-2005-olap-best-practice-white-paper.html" target="_blank">OLAP Design Best Practices for Analysis Services 2005</a></font></p>
<strong>Data Source Design Best Practices / 数据源设计最佳实践</strong>
<blockquote><p>Do use only supported OLEDB providers in a Data Source      <br />在数据源中仅仅使用被支持的OL&#8230;</p></blockquote>]]></description>
			<content:encoded><![CDATA[<p><font color="#ff8040">英文原文：<a href="http://www.imkevinyang.com/2009/05/analysis-service-2005-olap-best-practice-white-paper.html" target="_blank">OLAP Design Best Practices for Analysis Services 2005</a></font></p>
<h2><strong>Data Source Design Best Practices / 数据源设计最佳实践</strong></h2>
<blockquote><p>Do use only supported OLEDB providers in a Data Source      <br />在数据源中仅仅使用被支持的OLEDB提供程序。</p>
</blockquote>
<p>Analysis Service在设计和测试的时候都是以特定的OLE DB提供程序作为基准的。虽然其他的OLE DB提供程序也可以使用，而且选择数据源向导也允许你自由选择其他兼容的提供程序，但是不同提供程序之间的能力和行为是有一些微妙的不同之处的，即使连接到同一个数据库也可能存在不同。所以你应该尽可能地去使用那些被Analysis所支持的提供程序。要查看所有支持的提供程序，请访问：http://msdn2.microsoft.com/en-us/library/ms175608.aspx。 </p>
<blockquote><p>Do not use the .Net SqlClient Data Provider to connect to a SQL Server data source      <br />忌用.NET SqlClient 数据提供者连接SQL Server数据源。</p>
</blockquote>
<p>Analsysi Services使用本地代码运行（这样效率更高），因此如果使用的是本地提供程序的话，你可以获得更不错的性能。因此，不要使用.Net SqlClient数据提供程序，而是使用SQL Server的Microsoft OLE DB提供程序或者SQL Native Client提供程序作为替代。</p>
<h2><strong>Dimension Design Best Practices / 维度设计最佳实践</strong></h2>
<p>好的维度设计往往是一个好的Analysis Service OLAP数据库设计的一个重要组成部分。虽然Analysis Service向导已经为你做了很多工作，但是还是有必要重新审视下用向导生成的设计，确认属性、关联还有维度层次是否正确反应了底层数据，并且满足终端客户的需求。</p>
<blockquote><p>Do create attribute relationships wherever they exist in the data      <br />尽量创建属性关联(Attribute Relationships)如果它们的数据存在关联 </p>
</blockquote>
<p>属性关联是维度设计中最为重要的一部分。它们帮助服务器对数据的存储进行优化，对维度内的完整性进行检查，为成员提供了成员属性的特性，并且决定了MDX查询中一个维度层次的数据如何影响另外一个维度层次的数据。出于这些考虑，你需要花多一些时间在属性关联的设计上面，保证其正确反映了底层数据之间关系。</p>
<blockquote><p>Avoid creating attributes that will not be used      <br />避免创建不被使用的属性 </p>
</blockquote>
<p>属性增加了维度的复杂性和存储开销，一个维度中的属性的数量会对其性能产生比较显著的影响。特别是对于那些设置了AttributeHierarchyEnabled=true的属性。虽然SQL Server 2005 Analysis Service支持一个维度中添加很多的属性，但是设计过多不必要的属性往往会降低系统性能，使到改善终端用户体验变得更为困难。通常我们无需为维度表中的每个字段都建立一个属性。虽然Analysis Service向导总是会自动帮你选出维度表中所有的字段甚至关联表中的所有字段作为属性，但是一个好的设计是在开始的时候先把确定会使用到的字段添加为属性，以后如果有需要的话再向维度中添加其他的属性。为适应新需求而添加属性总比预先把所有潜在的属性都加上去然后再一个个删除更高效。</p>
<blockquote><p>Do not create hierarchies where an attribute of a lower level contains fewer members than an attribute of the level above </p>
<p>不要创建子级别属性成员数少于父级别属性成员数的维度层次</p>
</blockquote>
<p>如果存在这样的维度层次，那么通常意味着你的维度层次设计中，级别放置的顺序有问题。例如，City放置在State级别之上。也有可能是因为子级别的关键列缺少必要的字段，例如在[Quarter Number]级别之上的Year级别而不是在把Year设置在[Quarter with Year]之上。任何这些情况都会引起终端用户在使用和理解多维数据集时的困惑。</p>
<blockquote><p><strong>Do not</strong> include more than one non-aggregatable attribute per dimension       <br />在同一个维度中切勿包含一个以上的非聚合属性       </p>
</blockquote>
<p>对于非聚合属性，没有了All成员，因此对于每个非聚合属性默认情况下都会选中一个非“AlL &quot;的成员，即使在查询过程中没有显式指定该成员。因此，如果你在一个维度中包含了两个以上的非聚合属性，那么选取的属性之间就会产生冲突，最终得到的聚合指标可能就不是我们所期望的。</p>
<p>例如，在时间维度中，可能对[Calendar Year]或者[Fiscal Year]的成员进行sum聚合不是很有意义，但如果把两个属性同时设置为非聚合属性，那么当用户查询一个指定的[Calendar Year]的数据的时候，这个数据就会被[Fiscal Year]属性下的默认成员预先过滤了，除非用户同时显式指定了[Fiscal Year]的成员。糟糕的是，这两个属性之间不是并列的关系，而是重叠的关系。也就是说，这两个属性之间是互相影响的，我们很难保证显式指定的[Fiscal Year]成员和[Calendar Year]属性的成员之间有重叠，因而查询在查询其中一个属性时，我们很难得到该属性的全部数据的聚合值。</p>
<blockquote><p>Do use key columns that completely and correctly define the uniqueness of the members in an attribute      <br />正确使用关键列来保证成员在属性上的唯一性 </p>
</blockquote>
<p>通常情况下，一个简单的关键列就足够了，但有时候，我们需要使用多个列来同时决定属性的成员的唯一性。例如，我们很熟悉的时间维度中，[Month]属性就是使用了[Year]和[Month Name]作为关键列集合。这也是我们常说的复合主键，它将 “January of 1997”和“January of 1998”当作两个不同的成员。当你在时间维度层次中同时使用[Month]属性和[Year]属性时，“January of 1997”和“January of 1998”之间的区别就变得非常重要了。</p>
<blockquote><p>Do perform Process Index after doing a Process Update if the dimension contains flexible AttributeRelationships or a parent-child hierarchy      <br />如果维度上含有Flexible的属性关系或者含有父子层次，在做处理更新时候需要重做Process Index       </p>
</blockquote>
<p>一个聚合，若其中包含一个属性使用柔性关系直接或者间接的关联到关键属性上，那么这个聚合也被视为是柔性的。包含父子层次关系的聚合也被视为是柔性的。</p>
<p>当使用“Processing Update ”选项对维度进行处理时，所有涉及到此维度的柔性于聚合可能都会被丢弃，这取决于新维度数据的内容。这些聚合默认情况下是不会重建，因此必须显式的使用“Process Index ” 选项去重建这些聚合。</p>
<blockquote><p>Do use numeric keys for attributes that contain many members (&gt;1 million)      <br />给属性列使用数字类型，尤其含有百万记录成员的属性       </p>
</blockquote>
<p>使用数字属性列而不用字符串或者复合关键列会大大提高那些那些包含大量成员的属性。这个最佳实践类似于我们在关系型数据库中常常使用代理主键（通常是自增长数字主键）来替代业务主键，以使索引性能更佳，理念是类似的。你可以使用数字型列作为属性关键列，然后使用文本型列作为该属性的名字列，以展示给最终用户。一个指导原则就是，当你属性包含有超过一百万个成员时，一定要考虑使用数字型列作为属性关键列。</p>
<blockquote><p>Do not create redundant attribute relationships      <br />不要创建多余的属性关联，比如A-&gt;B, B-&gt;C, 则A-&gt;C不必手工创建       </p>
</blockquote>
<p>如果两个属性之间已经存在间接的关系，那么就不需要再为其建立多余的直接关联。多余的关联路径会对服务器处理造成问题，而且也不会对维度有任何好处。例如，如果我们已经创建了A-&gt;B, B-&gt;C的关联路径，那么 A-&gt;C 之间的路径就是多余的，应该删除掉。</p>
<blockquote><p>Do include the key columns of snowflake tables joined to nullable foreign keys as attributes that have NullProcessing set to UnknownMember      <br />如果维度表外键关联可能为NULL的列，则设置NullProcessing为UnknownMember       </p>
</blockquote>
<p>如果维度中用到的表的主键可能会被其他表当作外键引用，而其他表中的此外键字段可能为null，那么你最好要在维度设计中包含此主键作为一个属性，否则的话，OLAP服务器会在处理维度时会对这两张表发起一次Join查询。这会使到处理速度更慢。更重要的是，OLAP服务器默认用到的Join查询会排除掉任何外键字段包含null的行记录。因此对于此属性，一定要记住设置其NullProcess选项为UnknownMember。因为默认情况下，null字段在引擎处理属性时会被转化成0或者空值。这有时会造成错误，因为0可能指向一个合法的主键，所以可能会产生不正确的结果。为了更合适的处理null字段，你必须设置维度的UnknownMember属性为visible。多维数据集和维度向导已经帮你自动设置好此选项。但是，维度向导当遇到雪花型表结构时，允许你手动去除雪花结构表中的主键，如果此主键相关的外键可能为null，那么你千万要勾选这个主键。</p>
<p>如果你不想此属性展示给最终用户，那么你可以将其AttributeHierarchyVisible的选项设置为false。但是AttributeHierarchyEnabled选项必须设置为true，因为其他属性可能直接或者间接的关联到这个属性上，从而避免在维度处理过程中产生的不必要的join查询。</p>
<blockquote><p>Do set the RelationshipType property appropriately on AttributeRelationships based on whether the relationships between individual members change over time      <br />根据成员属性的不同特点设置合适的RelationshipType(Flexible或者Rigid)       </p>
</blockquote>
<p>不同属性之间的成员的关系，例如给定一个日期，看它的月份，或者给定一个用户，看它的性别，这些属性成员直接的关系一般都是不会发生变化的。其他属性关系，如给定一个区域，看它的销售人员，或者用户的婚姻状况，这些确实很可能随着时间的变化而发生改变。你应该将关系不会发生变化的属性之间设置。</p>
<p>正确设置这些关系类型，服务器可以对数据仓库的改变的处理流程和聚合的重建过程进行优化。默认情况下，此选项被设置为Flexible。</p>
<blockquote><p>Avoid using ErrorConfigurations with KeyDuplicate set to IgnoreError on dimensions      <br />为了检测数据唯一完整性，有的时候需要改变KeyDuplicate的默认值       </p>
</blockquote>
<p>当错误处理中的KeyDuplicate选项被设置为IgnoreError时，我们可能很难发现因为错误的关键列，错误的AttributeRelationships或者数据一致性问题导致的问题。因此大多数情况下，你最好修正你的设计，使到数据更可靠。IgnoreError对于原型设计可能比较有用，因为这样比较省事，默认的设置也是IgnoreError。因此，如果你已经完成原型设计了，那么最好改变KeyDuplicate的设置，以保证数据的完整性。</p>
<blockquote><p>Do define explicit default members for non-aggregatable Attributes      <br />对于非聚合属性定义默认成员       </p>
</blockquote>
<p>默认情况下，All成员被用作所有可聚合属性的默认成员。对于可聚合属性，这是没问题的，但是对于不可聚合属性，因为没有All成员，服务器就无法确定选择哪个成员作为默认成员，然后它就会随便的选择一个成员作为默认成员。这个默认成员会被应用在所有使用到这个属性维度层次但是却有没有显式指定成员的Mdx查询中。为了避免这种情况的发生，对于非聚合属性，我们要显式的制定一个默认成员。我们可以再属性的属性面板中设置，也可以通过cube脚本设置。</p>
<blockquote><p>Avoid creating user-defined hierarchies that do not have attribute relationships relating each level to the level above      <br />不要创建子级别和父级别没有关联关系的自定义层次       </p>
</blockquote>
<p>定义维度层次中级别之间的关系可以使服务器对其进行更有效的优化。</p>
<blockquote><p>Avoid creating diamond-shaped attribute relationships      <br />避免创建钻型属性关联      </p>
</blockquote>
<p>钻型关系指的是关系图中先分开又合并但又不存在冗余的这种情况。例如Day-&gt;Month-&gt;Year 和Day-&gt;Quarter-&gt;Year这两条关系线都使用的同一个起点和同一个终点，但是关系并没有重叠。这种关系也被称作多重路径关系，对于服务器而言，这样会造成二义性。如果实在需要保留这种设计，那么你可以通过定义包含每条关系路径的自定义维度层次来解决二义性的问题。</p>
<p>(关于钻行关联，可以参考这篇Blog以及AS2008可能会去除这个限制：http://sqlblog.com/blogs/mosha /archive/2007/06/07/katmai-june-ctp-attribute-relationships-tab.aspx ) </p>
<blockquote><p>Consider setting AttributeHierarchyEnabled to False on attributes that have cardinality that closely matches the key attribute      <br />对于那些表间关系和关键列很接近的属性，考虑设置AttributeHierarchyEnabled属性为false来禁用属性层次       </p>
</blockquote>
<p>虽然维度属性只能包含一个关键列，这样才能唯一标识一个值，但维度属性可以拥有其他属性作为附加的标识信息或细节信息。这些维度属性通常并不会被用作分组或者中心来查看聚合数据，例如电话号码之类的维度属性，通常人们更倾向于将其作为例如用户的附加属性来查看，而不会看从每个电话号码的维度层次去看聚合数据。因此将这些维度属性的AttributeHierarchyEnabled选项设置为False可以降低终端用户查看维度时的复杂性，同时对性能也有一定的提升。</p>
<p>如果你希望可以浏览这些维度属性，那么你可以设置AttributeHierarchyEnabled=true，然后将AttributeHierarchyOptimized设置为NotOptimized，将GroupingBehavior设置为DiscourageGrouping。这样，你还是可以提升性能，并且指示终端用户，此维度属性不建议用作分组聚合。</p>
<blockquote><p>Consider setting AttributeHierarchyVisible to False on the key attribute of parent-child dimensions      <br />设置父子维度的key attribute的AttributeHierarchyVisible为False       </p>
</blockquote>
<p>已经放置到父子维度层次结构中的关键属性默认情况下也会再生成一个属性层次，这通常没有什么必要，而且也会造成终端用户的迷惑。</p>
<blockquote><p>Avoid setting UnknownMember=Hidden      <br />避免设置UnknownMember=Hidden       </p>
</blockquote>
<p>如果你隐藏了unknownmember，那么可能会隐藏掉潜在的关系型数据库的一致性问题。而且隐藏的UnknownMember可能包含有聚合数据，因此展示给终端用户的数据加起来和OLAP服务器通过All成员聚合得到的数值可能就会不一致。因此，除非是原型设计，否则不推荐隐藏UnknownMember。</p>
<blockquote><p>Do use MOLAP storage mode for dimensions with outline calculations (custom rollups, semi-additive measures, and unary operators)      <br />对含有outline计算的维度记得使用MOLAP存储模式       </p>
</blockquote>
<p>包含自定义Rollups或者一元操作符的维度使用MOLAP存储模式可以显著提高性能。下面这些类型的维度也会受益：对于通过帐户维度进行聚合的指标时，帐户维度性能会所有提升；包含半可加性指标的分组中的第一个时间维度。</p>
<blockquote><p>Do use a 64 bit server if you have dimensions with more than 10 million members      <br />如果维度下成员含有千万个数量级，需要考虑使用64位的服务器了       </p>
</blockquote>
<p>如果维度下包含有千万数量级的成员，那么出于性能考虑，就必须使用到64位或者基于IA-64的服务器了。</p>
<blockquote><p>Do set the OrderBy property for time attributes and other attributes whose natural ordering is not alphabetical      <br />对于那些不是数字类型的属性(Attribute)，比如时间，记得设置它的OrderBy属性(Property)       </p>
</blockquote>
<p>默认情况下，服务器对于维度属性的成员使用按名字的进行字母排序。这种排序对于时间属性来说是特别不合适的。为了得到期望的排序行为，我们需要显式指定OrderBy和OrderByAttributes的选项。对于时间相关的属性，通常我们会设置date或者一个数值类型的列作为其排序依据。 </p>
<blockquote><p>Do expose a DateTime MemberValue for date attributes      <br />对于日期属性，尽量暴露它的MemberValue属性（有些客户端会根据这个属性来对待日期时间）       </p>
</blockquote>
<p>有一些客户端如Excel，会使用日期成员的MemberValue属性来获取相关的具体日期。当Excel发现其属性值为DateTime类型的话，Excel会将此成员作为DateTime类型来处理，这样就可以应用Excel的一些函数，同时也可以由Excel来对其作格式化和过滤。如果该维度属性对应的关键列只有一个，并且是DateTime类型的，同时命名列也没有设置，那么MemberValue会自动继承关键列。这种情况下，你不需要做任何额外的操作。但是，在其他情况下，你必须通过显式指定ValueColumn选项对应的列从而正确设置MemberValue属性。 </p>
<blockquote><p>Do set AttributeHierarchyEnabled to False, specify a ValueColumn and specify the MimeType of the ValueColumn on attributes that contain images      <br />对于图片属性，应该要设置AttributeHierarchyEnabled为False,并且设置它的MimeType为图片类型       </p>
</blockquote>
<p>因为在浏览一个包含图片信息的属性时没有值可以显示，因此你需要将该属性的属性维度层次设为隐藏，以避免用户直接浏览。为了帮助客户端识别并展示这些包含图片信息的属性，我们需要设置属性的值列，同时还需要将mime类型设置为相应的图片类型。</p>
<blockquote><p>Avoid setting IsAggregatable to False on any attribute other than the parent attribute in a parent-child dimension      <br />除了父子维度的parent属性外，不要设置属性的IsAggregatable为false       </p>
</blockquote>
<p>非聚合属性都包含一个不是All的默认成员，这些默认成员会影响到那些没有显式指定维度层次成员的Mdx查询。因为父子层次通常代表着用户非常感兴趣的浏览路径，因此在这种情况下用到非聚合属性是必要的，其他情况，尽量要避免非聚合属性的使用。</p>
<blockquote><p>Do set dimension and attribute Type properties correctly for Time, Account, and Geography dimensions      <br />对于时间，帐户，地理维度记得设置他们的维度和属性类型       </p>
</blockquote>
<p>对于时间维度，一定要注意正确设置每个维度属性的类型，因为时间相关的Mdx函数还有和时间维度相关的商业智能都会用到这些维度属性，正确设置其类型可以保证这些函数和商业智能得到你期望的结果。对于帐户维度，如果你用到了使用帐户进行聚合的指标，那么一定要注意正确设置账户维度的类型。地理类型虽然服务器没有提供内置的支持，但是正确设置其类型可以为客户端程序提供更多有用的信息。</p>
<p>一个常见的错误就是设置了维度的类型，但是没有设置维度属性的类型，或者反过来。另外一个常见的错误是不清楚这些类型的意义，从而设置错误。例如本该设置为[Month]类型的，结果设置成[Month of Year]类型。</p>
<blockquote><p>Consider creating user-defined hierarchies whenever you have a chain of related attributes in a dimension </p>
<p>如果维度中属性有一系列的关联关系，记得创建自定义层次      </p>
</blockquote>
<p>维度属性关系链通常代表着用户感兴趣的浏览路径，而且将其定义成用户自定义维度层次可以带来性能的提升。</p>
<blockquote><p>Do include all desired attributes of a logical business entity in a single dimension instead of splitting them up over several dimensions      <br />尽量在一个维度中把描述一个业务实体所有必要关联属性，而不是分到多个维度中       </p>
</blockquote>
<p>在Analysis Services 2000中，每一个维度层次事实上就是一个独立的维度，像性别，年龄这样的维度属性也被视作一个独立的维度。在Analysis Services 2005中，维度可以并且也应该包含一个业务实体的完整信息，包含相关的维度层次还有维度属性。但是这也不是说所有信息都必须塞到一个维度里面去，而是说，描述一个业务实体的完整信息应该包含在一个维度中，而不是分隔到多个维度里面。</p>
<p>对于此指导原则，有两个例外：</p>
<p>1. 因为一个维度只能包含一个父子结构的维度层次，因此如果你有多个父子层次，那么需要放到不同维度中。</p>
<p>2. 要在一个维度中用到多重join到某一个查询表，你必须创建一个独立的基于这个查询表的维度，然后将其作为一个引用维度。</p>
<blockquote><p>Do not combine unrelated business entities into a single dimension      <br />也不要把没有关联的多个业务实体放到同一个维度中       </p>
</blockquote>
<p>将独立的业务实体，例如客户和产品或者仓库和时间，放置到一个单一的维度中去，不但会使到模型容易让人迷惑，而且会造成查询性能的降低，因为auto-exist的特性会应用到维度内的任意两个属性之间。</p>
<p>换种说法，一个维度的关键属性需要唯一标识一个业务实体，而不是一个合并之后的业务实体。一般情况下，这要求对于关键属性只能有单一的关键列（非复合关键列）。</p>
<blockquote><p>Do set NullKeyConvertToUnknown to IgnoreError on the ErrorConfiguration on any measure groups that contain a dimension referenced through a nullable column      <br />对于任何度量组含有的维度如果引用含有NULL值，记得设置NullKeyConvertToUnknown为IgnoreError，并且UnknownMember设为Visible       </p>
</blockquote>
<p>默认情况下，当引擎在处理粒度属性的时候，null会被转化成0或者空字符串。这有时候会造成错误，因此0可能对应着一个合法的值，这样一来，结果可能就不是你想要的。为了避免这样的问题，你需要显式设置维度的UnknownMember为Visible，同时设置指标分组错误处理中的NullKeyConvertToUnknown选项为IgnoreError。</p>
<blockquote><p>Consider setting AttributeHierarchyVisible to False for attributes included in user-defined hierarchies      <br />考虑设置AttributeHierarchyVisible为false如果该属性在自定义的层次中被使用       </p>
</blockquote>
<p>如果一个属性已经被放到一个用户自定义的维度层次中去了，那么就没有必要再将其另起一个维度层次，这会让最终用户感觉到复杂。</p>
<p>一个常见的例子就是时间维度。向用户展示同一个属性的不同角度这是可以的。我们从Month的维度层次去看数据和从[Month-Quarter-Year]的维度层次去看数据都是很有价值的，不过，这两个维度层次中用到的Month其实是两个不同的属性。第一个显示的是“一月”这样的数据，而第二个显示的是“1998年一月”类似这样的数据。</p>
<blockquote><p>o not use proactive caching settings that put dimensions into ROLAP mode      <br />考虑性能不要使用Proactive caching设置维度为ROLAP模式（可设置OnlineMode为OnCacheComplete）             </p>
</p>
<p>    考虑到性能的原因，我们强烈建议在配置维度主动缓存策略时不要让其进入ROLAP模式。你需要设置OnlineMode属性为OnCachComplete（在存储选项面板中将“Bring online immediately”的勾去掉）。</p></blockquote>
<blockquote><p>Avoid making an attribute non-aggregatable unless it is at the end of the longest chain of attribute relationships in the dimension      <br />避免设置维度的属性（Attribute）为non-aggregatable除非它在一个相当长的属性关联关系链的末端       </p>
</blockquote>
<p>非聚合型属性会有一个非“All”的默认成员，这会影响到查询中那些没有显式指定这些非聚合属性成员的单元格的值。因此，你应该避免使用非聚合属性，除非这个属性很少被用到。因为长的属性链通常意味着用户非常感兴趣的分析路径，因此最好避免将非聚合型属性放置在人家不感兴趣的属性链上。</p>
<blockquote><p>Consider creating at least one user-defined hierarchy in each dimension that does not contain a parent-child hierarchy      <br />为非父子结构的维度创建至少一个自定义层次       </p>
</blockquote>
<p>大多数（但也不是全部）维度都会包含一些有价值的层次结构用来更好的展示数据。经常多维数据集向导或者维度向导没能检测到这些层次结构，在这种情况下，你就必须手动建立这些层次结构。</p>
<blockquote><p>Do set the InstanceSelection property on attributes to help clients determine the best way to display attributes for member selection      <br />设置Attribute的InstanceSelection属性，这样客户端工具可以在用户选择成员时候显示正常的属性值</p>
</blockquote>
<p>如果在一个列表中有太多的成员需要显示，那么客户端工具可以使用其他办法，如使用过滤类型的列表，来更好的展示这些成员。通过设置InstanceSelection属性，你可以根据列表中期望的成员数目来提示客户端程序使用合适的方式来展示这些成员</p>
<p>下面是一些指导性原则： </p>
<p><em>None</em></p>
<p>不要展示选择列表，让用户直接输入值。</p>
<p>&lt;100 成员，使用<em><strong>DropDown</strong></em></p>
<p>成员数目比较小，适合直接使用下拉列表框展示。</p>
<p>&lt; 500 成员，使用<em><strong>List</strong></em></p>
<p>成员数目过多，但是还不至于需要用到过滤的功能。</p>
<p>&lt; 5000 成员， 使用<em><strong>FilteredList</strong></em></p>
<p>成员数目已经很多了，需要用户进行过滤之后再展示。</p>
<p>&gt; 5000 成员，<em><strong>MandatoryFilter</strong></em></p>
<p>成员数目非常庞大，必须得过滤之后再展示。 </p>
<p>下面的C#代码演示了如何动态设置这个属性：</p>
<pre class="csharpcode"><span class="kwrd">if</span> ( estimatedCount &lt; 100 )     attribute.InstanceSelection = InstanceSelection.DropDown;
<span class="kwrd">else</span> <span class="kwrd">if</span> ( estimatedCount&lt; 500 )     attribute.InstanceSelection = InstanceSelection.List;
<span class="kwrd">else</span> <span class="kwrd">if</span> ( estimatedCount&lt; 5000 )     attribute.InstanceSelection = InstanceSelection.FilteredList;
<span class="kwrd">else</span>     attribute.InstanceSelection = InstanceSelection.MandatoryFilter;</pre>
<p><strong></strong></p>
<h2><strong>Cube Design Best Practices / 立方体设计最佳实践</strong></h2>
<p>1. Avoid including unrelated measure groups in the same cube<br />
  <br />避免在一个立方体中包含不关联的度量组 </p>
<p>2. Avoid having too many parent-child dimensions in a cube, especially when the dimension contains custom rollups or unary operators </p>
<p>避免在一个立方体中含有大量父子维度，尤其是维度含有自定义的Rollup或者一元操作符(?) </p>
<p>3. Do set AttributeHierarchyEnabled to False on any cube attributes that are below the level of granularity of all measure groups in the cube </p>
<p>当Attribute比立方体中所有度量组的粒度层次还要低的时候，可以设置它的AttributeHierarchyEnabled为false </p>
<p>4. Avoid having very big intermediate measure groups or dimensions of many-to-many dimensions </p>
<p>在多对多的维度中不要含有过大的度量组或者维度 </p>
<p>5. Consider using a processing query when using the scheduled polling option of proactive caching </p>
<p>当使用定时Proactive caching时候考虑使用processing query </p>
<p>6. Avoid creating multiple measure groups that have the same dimensionality and granularity </p>
<p>不要创建相同广度和力度的度量组 </p>
<p>7. Do put each distinct count measure into a separate measure group </p>
<p>在每个度量组中创建各自的计算度量 </p>
<p>8. Do set any explicit default members of role-playing dimensions directly on the cube dimensions </p>
<p>在立方体维度上直接设置role-playing维度的默认成员 </p>
<p>9. Do reuse dimensions multiple times in a cube instead of creating duplicates of a dimension </p>
<p>在立方体中重复利用已有的维度而不复制一个相同维度 </p>
<p>10. Avoid having cubes with a single dimension </p>
<p>切勿创建只有一个维度的立方体 </p>
<p>11. Do use the smallest numeric data type possible for measures </p>
<p>尽可能为度量使用最小数据类型 </p>
<p>12. Do ensure that the Collation property of OLAP objects is consistent with the collation of the relational source data when dealing with multilingual data </p>
<p>使用多语言数据时候，保持OLAP对象中的Collation和对应数据源中设置是一致的 </p>
<p>13. Do materialize referenced dimensions </p>
<p>物化(?)引用维度 </p>
<p>14. Avoid using linked dimensions, especially if your cube has outline calculations (custom rollups, semi-additive measures, or unary operators) or scripts </p>
<p>避免使用外接维度，尤其是立方体含有计算成员或者脚本</p>
<h2><strong>Partition Design Best Practices / 分区设计最佳实践</strong></h2>
<p>1. Avoid having partitions with more than 20 million rows<br />
  <br />分区数据控制在2000万条以内 </p>
<p>2. Avoid having many small partitions in a measure group </p>
<p>同一度量组内不要含有太多小分区 </p>
<p>3. Do set the Slice property on partitions that are ROLAP or partitions that use proactive caching </p>
<p>如果使用ROLAP模式或者Proactive caching，设置Slice属性进行切片 </p>
<p>4. Consider partitioning a distinct count measure group along the dimension used most often to query the distinct count measure </p>
<p>如果分区的度量组含有计算度量，记得同时包含使用次数最多的维度</p>
<h2><strong>Aggregation Design Best Practices / 聚集(聚合)设计最佳实践</strong></h2>
<p>1. Consider having aggregations for each partition of significant size<br />
  <br />对每个分区进行合适大小的聚集 </p>
<p>2. Do include the granularity attribute of the time dimension in aggregations for measure groups with semi-additive measures </p>
<p>对含有semi-additive度量的度量组，记得聚集时包含时间维度上的相关粒度的属性 </p>
<p>3. Do not build too many aggregations </p>
<p>不要建立太多聚集（&lt; 500） </p>
<p>4. Consider sharing aggregation designs between partitions of similar size and usage </p>
<p>对相似大小和使用特性的分区上使用公用相同的聚集（一般每个度量组有三种聚集即可） </p>
<p>5. Consider creating separate aggregation designs for partitions with significantly different size or usage </p>
<p>对不同大小不同使用的分区，创建单独的不同策略的聚集 </p>
<p>6. Do use a lower performance gain with regular aggregation design and a higher performance gain with usage-based optimization </p>
<p>一般聚集设计的时候，采用获取较低性能的方式，而对基于使用率优化时选择高性能获取方式 </p>
<p>7. Consider setting AggregationUsage to Unrestricted on high-use attributes that are not the key of a dimension and not in a hierarchy </p>
<p>对于不是key或者不在层次中的属性，设置它的AggregationUsage为Unrestricted以便系统在聚集时会优先考虑它 </p>
<p>8. Avoid Setting AggregationUsage to Full on Large Attributes </p>
<p>在大属性上避免设置AggregationUsage属性为Full </p>
<p>9. Do set member and row counts accurately for the partition when designing aggregations </p>
<p>设计聚集时候精确提供成员和记录行总数 </p>
<p>10. Consider including the granularity attribute of the intermediate dimensions of many-to-many dimensions in aggregations </p>
<p>在含有多对对的维度设计聚集时候，考虑包含中间维度上的粒度属性 </p>
<p>11. Do include in aggregations the granularity attribute of dimensions that contain unary operators or custom rollups </p>
<p>如果在维度上包含一元操作符或者自定义Rollup，在聚集时候要考虑它的粒度属性 </p>
<p>12. Avoid creating aggregations that are larger than one-third the size of the fact data </p>
<p>聚集大小不要超过事实表大小的三分之一 </p>
<p>13. Do remove aggregation designs that are not applied to any partitions </p>
<p>删除不适合任何分区的聚集 </p>
<p>14. Do not create aggregations that contain multiple attributes from the same attribute relationship chain </p>
<p>不要给来自同一属性关联组内的多个属性重复创建聚集 </p>
<p>15. Consider including in aggregations only those attributes with rigid relationships to their dimension keys </p>
<p>只包含那些刚性的维度建立聚集</p>

	标签：<a href="http://www.imkevinyang.com/tags/analysis-service%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5%e4%b8%ad%e6%96%87" title="Analysis Service最佳实践中文" rel="tag">Analysis Service最佳实践中文</a>, <a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/business-intelligence" title="Business Intelligence" rel="tag">Business Intelligence</a>, <a href="http://www.imkevinyang.com/tags/olap%e6%80%a7%e8%83%bd%e6%8c%87%e5%8d%97" title="OLAP性能指南" rel="tag">OLAP性能指南</a>, <a href="http://www.imkevinyang.com/tags/%e5%95%86%e4%b8%9a%e6%99%ba%e8%83%bd" title="商业智能" rel="tag">商业智能</a>, <a href="http://www.imkevinyang.com/categories/techarticles" title="技术随笔" rel="tag">技术随笔</a>, <a href="http://www.imkevinyang.com/tags/%e7%bf%bb%e8%af%91" title="翻译" rel="tag">翻译</a>, <a href="http://www.imkevinyang.com/tags/%e8%ae%be%e8%ae%a1" title="设计" rel="tag">设计</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/04/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5.html" title="Analysis Services 2005 OLAP设计最佳实践 (2009/04/02)">Analysis Services 2005 OLAP设计最佳实践</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/07/%e4%b8%bawordpress%e5%8d%9a%e5%ae%a2%e5%8a%a0%e9%80%9f%e6%b8%85%e7%90%86%e4%bd%a0%e7%9a%84%e4%b8%bb%e9%a2%98%e6%96%87%e4%bb%b6.html" title="为WordPress博客加速&mdash;&mdash;清理你的主题文件 (2009/07/26)">为WordPress博客加速&mdash;&mdash;清理你的主题文件</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/12/%e9%9d%9e%e5%b8%b8%e5%96%9c%e6%ac%a2%e7%8e%b0%e5%9c%a8google%e4%b8%bb%e9%a1%b5%e7%9a%84%e8%ae%be%e8%ae%a1.html" title="非常喜欢现在Google主页的设计 (2009/12/04)">非常喜欢现在Google主页的设计</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/07/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5-2.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Analysis Service 2005 OLAP Best Practice White Paper</title>
		<link>http://www.imkevinyang.com/2009/05/analysis-service-2005-olap-best-practice-white-paper.html</link>
		<comments>http://www.imkevinyang.com/2009/05/analysis-service-2005-olap-best-practice-white-paper.html#comments</comments>
		<pubDate>Fri, 22 May 2009 13:21:40 +0000</pubDate>
		<dc:creator>Kevin Yang</dc:creator>
				<category><![CDATA[BI/数据库]]></category>
		<category><![CDATA[OLAP]]></category>
		<category><![CDATA[多维数据集]]></category>
		<category><![CDATA[性能优化]]></category>
		<category><![CDATA[性能指南]]></category>
		<category><![CDATA[最佳实践]]></category>
		<category><![CDATA[维度设计]]></category>

		<guid isPermaLink="false">http://www.imkevinyang.com/2009/05/analysis-service-2005-olap-best-practice-white-paper.html</guid>
		<description><![CDATA[<font size="1">Data Source Design Best Practices</font>
<p><font size="1" face="Arial">OLAP databases in Analysis Services 2005 have several special requirements that are important to ensure trouble-free access to source data.</font></p>
<font size="1">D&#8230;</font>]]></description>
			<content:encoded><![CDATA[<h5><font size="1">Data Source Design Best Practices</font></h5>
<p><font size="1" face="Arial">OLAP databases in Analysis Services 2005 have several special requirements that are important to ensure trouble-free access to source data.</font></p>
<h6><font size="1">Do use only supported OLEDB providers in a Data Source</font></h6>
<p><font size="1" face="Arial">Analysis Services was designed and tested to work with a specific set of OLE DB providers. Although other OLE DB providers are available, and the Data Source Wizard lets you choose any compatible provider, the capabilities and behavior of different providers can differ substantially. This is true even for different providers that connect to the same database. Therefore, you should use only the supported providers.&#160; For a list of officially supported providers, see </font><font size="1" face="Arial">http://msdn2.microsoft.com/en-us/library/ms175608.aspx</font><font size="1" face="Arial">.</font></p>
<h6><font size="1">Do not use the .Net SqlClient Data Provider to connect to a SQL Server data source</font></h6>
<p><font size="1" face="Arial">Because the Analysis Services server runs in native code, you can get better performance by using a native provider. Therefore, do not use the .Net SqlClient Data Provider; instead, use the Microsoft OLE DB Provider for SQL Server or the SQL Native Client provider.</font></p>
<p><a href="http://technet.microsoft.com/zh-cn/library/cc966399%28en-us%29.aspx#mainSection"></a><a href="http://technet.microsoft.com/zh-cn/library/cc966399%28en-us%29.aspx#mainSection"><font size="1" face="Arial">Top Of Page</font></a></p>
<h5><font size="1">Dimension Design Best Practices</font></h5>
<p><font size="1" face="Arial">Good dimension design is the most important aspect of a well designed Analysis Services OLAP database. Although the wizards in Analysis Services do much of the work to get you started, it is important to review the design that is created by the wizard and ensure that the attributes, relationships, and hierarchies correctly reflect the data and match the needs of your end-users.</font></p>
<h6><font size="1">Do create attribute relationships wherever they exist in the data</font></h6>
<p><font size="1" face="Arial">Attribute relationships are an important part of dimension design.&#160; They help the server optimize storage of data, define referential integrity rules within the dimension, control the presence of member properties, and determine how MDX restrictions on one hierarchy affect the values in another hierarchy.&#160; For these reasons, it is important to spend some time defining attribute relationships that accurately reflect relationships in the data.</font></p>
<h6><font size="1">Avoid creating attributes that will not be used</font></h6>
<p><font size="1" face="Arial">Attributes add to the complexity and storage requirements of a dimension, and the number of attributes in a dimension can significantly affect performance.&#160; This is especially of attributes which have AttributeHierachyEnabled set to True. Although SQL Server 2005 Analysis Services can support many attributes in a dimension, having more attributes than are actually used decreases performance unnecessarily and can make the end-user experience more difficult. </font></p>
<p><font size="1" face="Arial">It is usually not necessary to create an attribute for every column in a table. Even though the wizards do this by default in Analysis Services 2005, a better design approach is to start with the attributes you know you'll need, and later add more attributes.&#160; Adding attributes as you discover they are needed is generally better a better practice than adding everything and then removing attributes.</font></p>
<h6><font size="1">Do not create hierarchies where an attribute of a lower level contains fewer members than an attribute of the level above</font></h6>
<p><font size="1" face="Arial">A hierarchy such as this is frequently an indication that your levels are in the incorrect order: for example, [City] above [State]. It might also indicate that the key columns of the lower level are missing a column: for example, [Year] above [Quarter Number] instead of [Year] above [Quarter with Year].&#160; Either of these situations will lead to confusion for end-users trying to use and understand the cube.</font></p>
<h6><font size="1">Do not include more than one non-aggregatable attribute per dimension</font></h6>
<p><font size="1" face="Arial">Because there is no All member, each non-aggregatable attribute will always have some non-all member selected, even if not specified in a query.&#160; Therefore, if you include multiple non-aggregatable attributes in a dimension, the selected attributes will conflict and produce unexpected numbers.&#160; </font></p>
<p><font size="1" face="Arial">For example, in a time dimension it might not make sense to sum the members of [Calendar Year] or [Fiscal Year], but if both are made non-aggregatable, whenever a user asks for data for a specific [Calendar Year] it will be filtered by the default [Fiscal Year] unless they also specify the [Fiscal Year].&#160; Worse, because [Calendar Year] and [Fiscal Year] do not align but overlap, it is difficult to obtain the full data for either a [Calendar Year] or a [Fiscal Year] because the one is filtered by the other.</font></p>
<h6><font size="1">Do use key columns that completely and correctly define the uniqueness of the members in an attribute</font></h6>
<p><font size="1" face="Arial">Usually a single key column is sufficient, but sometimes multiple key columns are necessary to uniquely identify members of an attribute.&#160; For example, it is common in time dimensions to have a [Month] attribute include both [Year] and [Month Name] as key columns.&#160; This is known as a <em>composite key</em> and identifies January of 1997 as being a different member than January of 1998. When you use [Month] in a time hierarchy that also contains [Year], this distinction between January of 1997 and January of 1998 is important.&#160; </font></p>
<p><font size="1" face="Arial">It may also make sense to have a separate [Month of Year] attribute that has only [Month Name] as the key.&#160; This [Month of Year] attribute contains a single January member that spans all years, which can be useful for comparing seasonal data. However, this attribute should not be used in a hierarchy together with [Year] because there is no relationship between [Month of Year] and [Year].&#160; </font></p>
<p><font size="1" face="Arial">Similar distinctions between [Quarter] and [Quarter of Year], [Semester] and [Semester of Year], and so on should also be made by setting appropriate key columns.</font></p>
<h6><font size="1">Do perform Process Index after doing a Process Update if the dimension contains flexible AttributeRelationships or a parent-child hierarchy</font></h6>
<p><font size="1" face="Arial">An aggregation is considered flexible if any attribute included in the aggregation is related, either directly or indirectly, to the key of its dimension through an AttributeRelationship with RelationshipType set to Flexible.&#160; Aggregations that include parent-child hierarchies are also considered flexible. </font></p>
<p><font size="1" face="Arial">When a dimension is processed by using the Process Update option, any flexible aggregations that the dimension participates in might be dropped, depending on the contents of the new dimension data.&#160; These aggregations are not rebuilt by default, so Process Index must then be explicitly performed to rebuild them.</font></p>
<h6><font size="1">Do use numeric keys for attributes that contain many members (&gt;1 million)</font></h6>
<p><font size="1" face="Arial">Using a numeric key column instead of a string key column or a composite key will improve the performance of attributes that contain many members.&#160; This best practice is based on the same concept as using surrogate keys in relational tables for more efficient indexing.&#160; You can specify the numeric surrogate column as the key column and still use a string column as the name column so that the attribute members appear the same to end-users. As a guideline, if the attribute has more than one million members, you should consider using a numeric key.</font></p>
<h6><font size="1">Do not create redundant attribute relationships</font></h6>
<p><font size="1" face="Arial">Do not create attribute relationships that are transitively implied by other attribute relationships.&#160; The alternative paths created by these redundant attribute relationships can cause problems for the server and are of no benefit to the dimension.&#160; For example, if the relationships A-&gt;B, B-&gt;C, and A-&gt;C have been created, A-&gt;C is redundant and should be removed.</font></p>
<h6><font size="1">Do include the key columns of snowflake tables joined to nullable foreign keys as attributes that have NullProcessing set to UnknownMember</font></h6>
<p><font size="1" face="Arial">If tables that are used in a dimension are joined on a foreign key column that might contain nulls, it is important that you include in your design an attribute whose key column is the corresponding key in the lookup table. Without such an attribute, the OLAP server would have to issue a query to join the two tables during dimension processing.&#160; This makes processing slower; moreover, the default join that is created by the OLAP server would exclude any rows that contain nulls in the foreign key column.&#160; It is important to set the NullProcessing option on the key column of this attribute to UnknownMember.&#160; The reason is that, by default, nulls are converted to zeros or blanks when the engine processes attributes.&#160; This can be dangerous when you are processing a nullable foreign key. Conversion of a null to zero at best produces an error; in the worst case, the zero may be a legitimate value in the lookup table, thereby producing incorrect results. </font></p>
<p><font size="1" face="Arial">To handle nullable foreign keys correctly, you must also set UnknownMember to Visible on the dimension. The Cube Wizard and Dimension Wizard currently set this property automatically; however, the Dimension Wizard lets you manually de-select the key attribute of snowflake tables. You must not deselect the key column if the corresponding foreign key is nullable.</font></p>
<p><font size="1" face="Arial">If you do not want to browse the attribute that contains the lookup table key column, you can set AttributeHierarchyVisible to False.&#160; However, AttributeHierarchyEnabled must be set to True because it is necessary that all other attributes in the lookup table be directly or indirectly related to the lookup key attribute in order to avoid the automatic creation of new joins during dimension processing.</font></p>
<h6><font size="1">Do set the RelationshipType property appropriately on AttributeRelationships based on whether the relationships between individual members change over time</font></h6>
<p><font size="1" face="Arial">The relationships between members of some attributes, such as dates in a given month or the gender of a customer, are not expected to change.&#160; Other relationships, such as salespeople in a given region or the marital status of a customer, are more prone to change over time.&#160; You should set RelationshipType to Flexible for those relationships that are expected to change and set RelationshipType to Rigid for relationships that are not expected to change.</font></p>
<p><font size="1" face="Arial">When you set RelationshipType appropriately, the server can optimize the processing of changes and re-building of aggregations.</font></p>
<p><font size="1" face="Arial">By default, the user interface always sets RelationshipType to Flexible.</font></p>
<h6><font size="1">Avoid using ErrorConfigurations with KeyDuplicate set to IgnoreError on dimensions</font></h6>
<p><font size="1" face="Arial">When KeyDuplicate is set to IgnoreError, it can be difficult to detect problems with incorrect key columns, incorrectly defined AttributeRelationships, and data consistency issues.&#160; Instead of using the IgnoreError option, in most cases it is better to correct your design and clean the data.&#160; The IgnoreError option may be useful in prototypes where correctness is less of a concern. Be aware that the default value for KeyDuplicate is IgnoreError. Therefore, it is important to change this value after prototyping is complete to ensure data consistency.</font></p>
<h6><font size="1">Do define explicit default members for non-aggregatable attributes</font></h6>
<p><font size="1" face="Arial">By default, the All member is used as the default member for aggregatable attributes. This default works very well for aggregatable attributes, but non-aggregatable attributes have no obvious choice for the server to use as a default member, therefore a member will be selected arbitrarily. This arbitrarily selected member is then selected whenever the attribute is not explicitly included in an MDX query. To avoid this, it is important to explicitly set a default value for each non-aggregatable attribute.&#160; </font></p>
<p><font size="1" face="Arial">Default members can be explicitly set either on the DimensionAttribute or in the cube script.</font></p>
<h6><font size="1">Avoid creating user-defined hierarchies that do not have attribute relationships relating each level to the level above</font></h6>
<p><font size="1" face="Arial">Having attribute relationships between every level in a hierarchy makes the hierarchy strong and enables significant server optimizations.</font></p>
<h6><font size="1">Avoid creating diamond-shaped attribute relationships</font></h6>
<p><font size="1" face="Arial">A <em>Diamond-shaped relationship</em> refers to a chain of attribute relationships that splits and rejoins but contains no redundant relationships.&#160; For example, Day-&gt;Month-&gt;Year and Day-&gt;Quarter-&gt;Year have the same start and end points, but do not have any common relationships.&#160; The presence of multiple paths can create some ambiguity on the server.&#160; If preserving the multiple paths is important, it is strongly recommended that you resolve the ambiguity by creating user hierarchies that contain all the paths.</font></p>
<h6><font size="1">Consider setting AttributeHierarchyEnabled to False on attributes that have cardinality that closely matches the key attribute</font></h6>
<p><font size="1" face="Arial">When an attribute contains roughly one value for each distinct value of the key attribute, it usually means that the attribute contains only alternative identification information or secondary details.&#160; Such attributes are usually not interesting to pivot or group by.&#160; For example, the Social Security number or telephone number may be interesting properties to view, but there is very little value in being able to pivot and group based on SSN or telephone.&#160; Setting AttributeHierarchyEnabled to False on such attributes will reduce the complexity of the dimension for end-users and improve its performance.</font></p>
<p><font size="1" face="Arial">If you want to be able to browse such attributes, you can set AttributeHierarchyEnabled to True; however, you should consider setting AttributeHierarchyOptimized to NotOptimized and setting GroupingBehavior to DiscourageGrouping. By setting these properties, you can improve performance and indicate to the users that the attribute is not very useful for grouping.</font></p>
<h6><font size="1">Consider setting AttributeHierarchyVisible to False on the key attribute of parent-child dimensions</font></h6>
<p><font size="1" face="Arial">Because the members of the key attribute are also contained in the parent-child hierarchy in a more organized manner, it is usually unnecessary and confusing to the end-user to expose the flat list of members contained in the key attribute.</font></p>
<h6><font size="1">Avoid setting UnknownMember=Hidden</font></h6>
<p><font size="1" face="Arial">When you suppress unknown members, the effect is to hide relational integrity issues; moreover, because hidden members might contain data, results might appear not to add up. Therefore, we recommend that you avoid use of this setting except in prototype applications.</font></p>
<h6><font size="1">Do use MOLAP storage mode for dimensions with outline calculations (custom rollups, semi-additive measures, and unary operators)</font></h6>
<p><font size="1" face="Arial">Dimensions that contain custom rollups or unary operators will perform significantly better using MOLAP storage.&#160; The following dimension types will also benefit from using MOLAP storage: an Account dimension in a measure group that contains measures aggregated using ByAccount; the first time dimension in a measure group that contains other semi-additive measures.</font></p>
<h6><font size="1">Do use a 64 bit server if you have dimensions with more than 10 million members</font></h6>
<p><font size="1" face="Arial">If a dimension contains more than 10 million members, using an x64 or an IA-64-based server is recommended for better performance.</font></p>
<h6><font size="1">Do set the OrderBy property for time attributes and other attributes whose natural ordering is not alphabetical</font></h6>
<p><font size="1" face="Arial">By default, the server orders attribute members alphabetically, by name.&#160; This ordering is especially undesirable for time attributes.&#160; To obtain the desired ordering, use the OrderBy and OrderByAttributes properties and explicitly specify how you want the members ordered.&#160; For time-based attributes, there is frequently a date or numeric key column that can be used to obtain the correct chronological ordering.</font></p>
<h6><font size="1">Do expose a DateTime MemberValue for date attributes</font></h6>
<p><font size="1" face="Arial">Some clients, such as Excel, will take advantage of the MemberValue property of date members and use the DateTime value that is exposed. When Excel recognizes the value as DateTime, Excel can treat the value as a date type and apply date functions to the value, as well as provide better formatting and filtering.&#160; If the key column is a single DateTime column and the name column has not been set, this MemberValue is automatically derived from the key column and no action is necessary.&#160; However, in other cases, you can ensure that the MemberValue is DateTime by explicitly specifying the ValueColumn property of the attribute. </font></p>
<h6><font size="1">Do set AttributeHierarchyEnabled to False, specify a ValueColumn and specify the MimeType of the ValueColumn on attributes that contain images</font></h6>
<p><font size="1" face="Arial">Because there is no value in browsing the member names of an attribute that contains an image, you should disable browsing by setting AttributeHierarchyEnabled to False.&#160; To help clients recognize and display the member property of the attribute as an image, specify the ValueColumn property of the attribute and then set MimeType to an appropriate image type.</font></p>
<h6><font size="1">Avoid setting IsAggregatable to False on any attribute other than the parent attribute in a parent-child dimension</font></h6>
<p><font size="1" face="Arial">Non-aggregatable attributes have non-all default members. These default members affect the result of queries whenever the attributes are not explicitly included.&#160; Because parent-child hierarchies generally represent the most interesting exploration path in dimensions that contain them, it is best to avoid having non-aggregatable attributes other than the parent attribute.</font></p>
<h6><font size="1">Do set dimension and attribute Type properties correctly for Time, Account, and Geography dimensions</font></h6>
<p><font size="1" face="Arial">For time dimensions, it is important to set the dimension and attribute types correctly so that time-related MDX functions and the time intelligence of the Business Intelligence Wizard can work correctly.&#160; For Account dimensions, it is similarly important to set appropriate account types when using measures with the aggregate function ByAccount.&#160; Geography types are not used by the server, but provide information for client applications.</font></p>
<p><font size="1" face="Arial">A common mistake is to set the Type property on a dimension but not on an attribute, or vice-versa. Another common mistake when configuring time dimensions is to confuse the different time attribute types, such as [Month] and [Month of Year].</font></p>
<h6><font size="1">Consider creating user-defined hierarchies whenever you have a chain of related attributes in a dimension</font></h6>
<p><font size="1" face="Arial">Chains of related attributes usually represent an interesting navigation path for end-users, and defining hierarchies for these will also provide performance benefits.</font></p>
<h6><font size="1">Do include all desired attributes of a logical business entity in a single dimension instead of splitting them up over several dimensions</font></h6>
<p><font size="1" face="Arial">In Analysis Services 2000, each hierarchy was in reality a separate dimension and attributes such as gender and age would also be separate dimensions.&#160; In Analysis Services 2005, a dimension can and should contain the complete information about a logical business entity, including multiple hierarchies and many attributes.&#160; This does not mean that every piece of information available must be included in the dimension, but rather that any desired information should be included in one dimension instead of split over many dimensions.</font></p>
<p><font size="1" face="Arial">There are two exceptions to this guideline:</font></p>
<ol>
<li>
<p><font size="1" face="Arial">A dimension can only contain one parent-child hierarchy.</font></p>
</li>
<li>
<p><font size="1" face="Arial">To model multiple joins to a lookup table within a dimension's schema, you must create a separate dimension based on the lookup table and then use this as a referenced dimension.</font></p>
</li>
</ol>
<h6><font size="1">Do not combine unrelated business entities into a single dimension</font></h6>
<p><font size="1" face="Arial">Combining attributes of independent business entities, such as customer and product or warehouse and time, into a single dimension will not only create a confusing model, but also reduce query performance because auto-exist will be applied across attributes within the dimension.</font></p>
<p><font size="1" face="Arial">Another way to state this rule is that the values of the key attribute of a dimension should uniquely identify a single business entity and not a combination of entities.&#160; Generally this means having a single column key for the key attribute.</font></p>
<h6><font size="1">Do set NullProcessing to UnknownMember on each attribute that has nulls and is used to join to a referenced dimension</font></h6>
<p><font size="1" face="Arial">By default, nulls are converted to zeros or blanks when the engine processes attributes.&#160; This can be dangerous when processing a nullable foreign key, because if a null is converted to zero when zero is a legitimate value in the reference dimension, the join on the values can produce incorrect results. At best, conversion to zero will produce an error.</font></p>
<p><font size="1" face="Arial">To prevent these errors, you must also set UnknownMember to Visible on the referenced dimension.</font></p>
<p><font size="1" face="Arial">The Cube Wizard in SQL Server 2005 Analysis Services handles both settings automatically, except when dealing with existing dimensions where UnknownMember is not set to Visible.</font></p>
<h6><font size="1">Do set NullKeyConvertToUnknown to IgnoreError on the ErrorConfiguration on any measure groups that contain a dimension referenced through a nullable column</font></h6>
<p><font size="1" face="Arial">By default, nulls are converted to zeros or blanks when the engine processes granularity attributes.&#160; This can be dangerous when you are processing a nullable foreign key, because if a null value is converted to zero and zero is a legitimate value in the dimension, the join can produce incorrect results. At best, the conversion will produce errors.</font></p>
<p><font size="1" face="Arial">To prevent conversion of nulls, you must also set UnknownMember to Visible on the dimension.</font></p>
<p><font size="1" face="Arial">The Cube Wizard in SQL Server 2005 Analysis Services handles these settings automatically, except when dealing with existing dimensions where UnknownMember is not set to Visible.</font></p>
<h6><font size="1">Consider setting AttributeHierarchyVisible to False for attributes included in user-defined hierarchies</font></h6>
<p><font size="1" face="Arial">It is usually not necessary to expose an attribute in its own single level hierarchy when that attribute is included in a user-defined hierarchy.&#160; This duplication only complicates the end-user experience without providing additional value.&#160; </font></p>
<p><font size="1" face="Arial">One common case in which it is appropriate to present two views of an attribute is in time dimensions.&#160; The ability to browse by [Month] and the ability to browse by [Month-Quarter-Year] are both very valuable. However, these two month attributes are actually separate attributes.&#160; The first contains only the month value such as “January” while the second contains the month and the year such as “January 1998”.</font></p>
<h6><font size="1">Do not use proactive caching settings that put dimensions into ROLAP mode</font></h6>
<p><font size="1" face="Arial">For performance reasons, we strongly discourage the use of dimension proactive caching settings that may put the dimension in ROLAP mode.&#160; To ensure that a dimension with proactive caching enabled will never enter ROLAP mode, you should set the OnlineMode property to OnCacheComplete.&#160; You can also prevent use of ROLAP mode by deselecting the Bring online immediately check box in the Storage Options dialog box.</font></p>
<h6><font size="1">Avoid making an attribute non-aggregatable unless it is at the end of the longest chain of attribute relationships in the dimension</font></h6>
<p><font size="1" face="Arial">Non-aggregatable attributes have non-all default members that affect the result of queries in which values for those attributes are not explicitly specified.&#160; Therefore, you should avoid making an attribute non-aggregatable unless that attribute is regularly used.&#160; Because the longest chain of attributes generally represents the most interesting exploration path for users, it is best to avoid having non-aggregatable attributes in other, less interesting chains.</font></p>
<h6><font size="1">Consider creating at least one user-defined hierarchy in each dimension that does not contain a parent-child hierarchy</font></h6>
<p><font size="1" face="Arial">Most (but not all) dimensions contain some hierarchical structure to the data which is worth exposing in the cube.&#160; Frequently the Cube Wizard or Dimension Wizard will not detect this hierarchy. In these cases, you should define a hierarchy manually.</font></p>
<h6><font size="1">Do set the InstanceSelection property on attributes to help clients determine the best way to display attributes for member selection</font></h6>
<p><font size="1" face="Arial">If there are too many members to display in a single list, the client user interface can use other methods, such as filtered lists, to display the members. By setting the InstanceSelection property, you provide a hint to client applications to suggest how a list of items should be displayed, based on the expected number of items in the list.</font></p>
<p><font size="1" face="Arial">Recommended guidelines for setting this property are as follows: </font></p>
<p><font size="1" face="Arial">Property Value </font></p>
<p><font size="1" face="Arial">Description </font></p>
<p><font size="1" face="Arial">Guidelines</font></p>
<p><font size="1" face="Arial">None</font></p>
<p><font size="1" face="Arial">Do not display a selection list. Enable users to enter values directly.</font></p>
<p><font size="1" face="Arial">DropDown</font></p>
<p><font size="1" face="Arial">The number of items is small enough to display in a drop-down list.</font></p>
<p><font size="1" face="Arial">&lt;100 members</font></p>
<p><font size="1" face="Arial">List</font></p>
<p><font size="1" face="Arial">The number of items is too large for a drop-down list but does not require filtering.</font></p>
<p><font size="1" face="Arial">&lt; 500 members</font></p>
<p><font size="1" face="Arial">FilteredList</font></p>
<p><font size="1" face="Arial">The number of items is large enough to require users to filter the items to be displayed.</font></p>
<p><font size="1" face="Arial">&lt; 5000 members</font></p>
<p><font size="1" face="Arial">MandatoryFilter</font></p>
<p><font size="1" face="Arial">The number of items is so large that the display must always be filtered. </font></p>
<p><font size="1" face="Arial">&gt; 5000 members</font></p>
<p><font size="1" face="Arial">The following C# code sample shows how to set the property dynamically:</font></p>
<pre><font size="1" face="Arial">if ( estimatedCount &lt; 100 )&#160;&#160;&#160;&#160; attribute.InstanceSelection = InstanceSelection.DropDown;
else if ( estimatedCount&lt; 500 )&#160;&#160;&#160;&#160; attribute.InstanceSelection = InstanceSelection.List;
else if ( estimatedCount&lt; 5000 )&#160;&#160;&#160;&#160; attribute.InstanceSelection = InstanceSelection.FilteredList;
else&#160;&#160;&#160;&#160; attribute.InstanceSelection = InstanceSelection.MandatoryFilter;</font></pre>
<p><a href="http://technet.microsoft.com/zh-cn/library/cc966399%28en-us%29.aspx#mainSection"></a><a href="http://technet.microsoft.com/zh-cn/library/cc966399%28en-us%29.aspx#mainSection"><font size="1" face="Arial">Top Of Page</font></a></p>
<h5><font size="1">Cube Design Best Practices</font></h5>
<p><font size="1" face="Arial">Well-designed cubes will better match the needs of your end-users. The following best practices can improve usability and also performance of the cube.</font></p>
<h6><font size="1">Avoid including unrelated measure groups in the same cube</font></h6>
<p><font size="1" face="Arial">Having many measure groups in a cube can adversely affect the query performance of the cube, even for queries that only use a single measure group.&#160; If your DSV contains many potential fact tables and they will not usually be used together, consider creating multiple smaller cubes containing topic areas that are used together.&#160; Then, you can enable occasional cross-topic querying by creating linked measure groups that join together all measure groups in a special cross-topic cube.</font></p>
<h6><font size="1">Avoid having too many parent-child dimensions in a cube, especially when the dimension contains custom rollups or unary operators</font></h6>
<p><font size="1" face="Arial">Parent-child dimensions, especially those that contain custom rollups and unary operators, are very powerful and flexible.&#160; However, in order to prevent poor query performance, such parent-child dimensions should only be used as necessary.</font></p>
<h6><font size="1">Do set AttributeHierarchyEnabled to False on any cube attributes that are below the level of granularity of all measure groups in the cube</font></h6>
<p><font size="1" face="Arial">Attributes are considered below the level of granularity for a measure group when no chain of attribute relationships exists between the granularity attribute and the attribute in question.&#160; Such attributes will never have any data associated with them in the cube and will only confuse end-users.&#160; For example, if a time dimension contains day, week, month and year attributes, whereas an inventory cube contains only data updated on a weekly basis, it is best to disable the day attribute for this cube by setting AttributeHierarchyEnabled to False for the day attribute only. </font></p>
<h6><font size="1">Avoid having very big intermediate measure groups or dimensions of many-to-many dimensions</font></h6>
<p><font size="1" face="Arial">Having very big intermediate measure groups could lead to potential performance issues in many-many dimensions. “Very big” means larger than the measure group or more than one million rows. You can also experience performance issues when using very big dimensions in many-many dimension relationships.</font></p>
<h6><font size="1">Consider using a processing query when using the scheduled polling option of proactive caching</font></h6>
<p><font size="1" face="Arial">A polling query is typically a singleton query that returns a value Analysis Services can use to determine whether changes have been made to a table or other relational object.&#160; The polling query tells the proactive caching mechanism when it must read in new data.&#160; </font></p>
<p><font size="1" face="Arial">In contrast, a processing query is a query that returns a rowset that contains the changes made to a table associated with an Analysis Services object since the last time the table was polled, in order to incrementally update the multidimensional OLAP (MOLAP) cache for the object. Therefore, the processing query tells the proactive caching mechanism what data is new.&#160; By setting the processing query, you can configure the system to read and process only the new data, instead of re-reading and re-processing the whole table.</font></p>
<h6><font size="1">Avoid creating multiple measure groups that have the same dimensionality and granularity </font></h6>
<p><font size="1" face="Arial">Having too many measure groups can adversely affect performance.&#160; Moreover, the presence of many similar measure groups presents a more complex model to the end-user by dividing data on a common subject.&#160; Instead, you should consider creating a single measure group that contains multiple partitions.&#160; The common exception to this guideline is distinct count measures, which for performance reasons should be in their own measure groups.</font></p>
<h6><font size="1">Do put each distinct count measure into a separate measure group</font></h6>
<p><font size="1" face="Arial">Put each distinct count measure into its own measure group. This will improve performance.</font></p>
<h6><font size="1">Do set any explicit default members of role-playing dimensions directly on the cube dimensions</font></h6>
<p><font size="1" face="Arial">A dimension that has been given a different name in a cube than it has outside the cube is said to be role-playing.&#160; The name that is used in the cube is known as the role the dimension plays within that cube.&#160; Role-playing is used most often when a dimension plays more than one role in a cube.&#160; For example, the [Order Date] and [Ship Date] cube dimensions are both based on the [Date] dimension, but are assigned different names, or roles.</font></p>
<p><font size="1" face="Arial">Because such a dimension has a different name in the cube, whereas the default member expression is evaluated in the context of the cube, any explicit reference to the original dimension name in the default member will be invalid.&#160; To specify the default member on the cube dimension, you can use the following syntax in the cube’s calculation script: </font></p>
<pre><font size="1" face="Arial">ALTER CUBE CurrentCube UPDATE DIMENSION &lt;dimension name&gt;, DEFAULT_MEMBER='&lt;default member&gt;'</font></pre>
<p><font size="1" face="Arial">This has the added benefit of enabling different default members for each of the roles a dimension plays in a cube. Such role specific default members frequently make sense from the business perspective.</font></p>
<h6><font size="1">Do reuse dimensions multiple times in a cube instead of creating duplicates of a dimension</font></h6>
<p><font size="1" face="Arial">In Analysis Services 2000, it was necessary to create new copies of a dimension for role-playing. In other words, to use two identical date dimensions, [Ship Date] and [Order Date], you needed to have two separate dimensions.&#160; However, in Analysis Services 2005, this is not necessary and should be avoided as it will introduce unnecessary storage and maintenance costs.</font></p>
<h6><font size="1">Avoid having cubes with a single dimension</font></h6>
<p><font size="1" face="Arial">If a cube has only one dimension, you should consider splitting this single dimension into multiple dimensions based on logical business entities.&#160; Typically, a cube contains only a single dimension because it was based on a single de-normalized table, which the Cube Wizard was unable to break into multiple dimensions.&#160; </font></p>
<p><font size="1" face="Arial">This single dimension almost always contains multiple logical business entities. From the perspective of the user, the different business entities would be more cleanly modeled and navigated as separate dimensions.</font></p>
<h6><font size="1">Do use the smallest numeric data type possible for measures</font></h6>
<p><font size="1" face="Arial">The data type of measures must be large enough to hold the largest aggregated value (the &quot;all&quot; value) but should be no larger than necessary to reduce storage costs.</font></p>
<h6><font size="1">Do ensure that the Collation property of OLAP objects is consistent with the collation of the relational source data when dealing with multilingual data</font></h6>
<p><font size="1" face="Arial">Collation controls both the sorting and equivalence of strings; therefore it is important to have the Analysis Services server use the appropriate collation for the data. If you use the wrong collation, you might see strange results, especially if the column is used for a distinct count measure.&#160; </font></p>
<p><font size="1" face="Arial">Collations can be set at the level of the server, database, cube, and dimension and also on individual column bindings.&#160; The important point is to have the collation of your OLAP objects be consistent with the collation of the relational data on which they are built.&#160; For example, the caption columns of translations usually contain text in another language and are therefore likely to have a different collation.</font></p>
<h6><font size="1">Do materialize referenced dimensions</font></h6>
<p><font size="1" face="Arial">To improve performance, reference dimensions should be materialized.&#160; The only exception to this is the rare case when you are creating a reference dimension relationship between a local dimension and a linked measure group.&#160; When a reference dimension is created by using the user interface for SQL Server 2005 Analysis Services, it will be materialized by default.&#160; </font></p>
<h6><font size="1">Avoid using linked dimensions, especially if your cube has outline calculations (custom rollups, semi-additive measures, or unary operators) or scripts</font></h6>
<p><font size="1" face="Arial">Although it is possible to use dimensions linked from another database (or server) with a local measure group, this will adversely affect performance and should be avoided when possible. Instead, consider creating a local copy of the dimension. Even on the same server,&#160;&#160; you should avoid linked dimensions.</font></p>
<p><a href="http://technet.microsoft.com/zh-cn/library/cc966399%28en-us%29.aspx#mainSection"></a><a href="http://technet.microsoft.com/zh-cn/library/cc966399%28en-us%29.aspx#mainSection"><font size="1" face="Arial">Top Of Page</font></a></p>
<h5><font size="1">Partition Design Best Practices</font></h5>
<p><font size="1" face="Arial">Following some simple best practices can help ensure an effective data storage strategy that will enable the OLAP server to scale efficiently to your data volumes.</font></p>
<h6><font size="1">Avoid having partitions with more than 20 million rows</font></h6>
<p><font size="1" face="Arial">Large partitions should generally be broken up into multiple smaller partitions for better performance. As a rule, no partition should have more than 20 million rows.</font></p>
<h6><font size="1">Avoid having many small partitions in a measure group</font></h6>
<p><font size="1" face="Arial">Small partitions should generally be combined into fewer, larger partitions for better performance. As a guideline, consider combining partitions when a measure group has more than five partitions with less than two million rows each.</font></p>
<h6><font size="1">Do set the Slice property on partitions that are ROLAP or partitions that use proactive caching</font></h6>
<p><font size="1" face="Arial">Use of the Slice property lets the server know which partitions it must look in for data to answer queries.&#160; For example, if a partition contains a slice that states it contains only data for 2002, when a query requests sales in 2003, the server will know it does not have to look in that partition in order to answer that query.</font></p>
<p><font size="1" face="Arial">For MOLAP partitions, you do not have to specify the slice because the server will be able to figure out the relevant partitions after the data has been processed.&#160; However, when you use proactive caching, it’s a good idea to specify the slice manually since the partition may be treated as ROLAP during the construction of the MOLAP cache.&#160; (If a slice is manually specified on a MOLAP partition and that slice is not consistent with the data that is contained in the partition, the server will raise an error during processing of the data.)&#160; </font></p>
<p><font size="1" face="Arial">For ROLAP partitions, a slice should be specified or the partition will always have to be queried.&#160; </font></p>
<p><font size="1" face="Arial">To set the Slice property in Business Intelligence Development Studio, select the partition in the Partitions tab of the Cube Editor. In the Properties window, click the text box for the Slice property.&#160; Click the ellipsis (...) button to open the Partition Slice dialog box. You can type an MDX expression to specify the member on which you want to slice.&#160; To slice on multiple hierarchies, enter a tuple containing the members on which you want to slice.</font></p>
<h6><font size="1">Consider partitioning a distinct count measure group along the dimension used most often to query the distinct count measure</font></h6>
<p><font size="1" face="Arial">When partitioning a measure group that includes a distinct count measure, consider partitioning the measure group along the dimension that is most often used to query distinct count measure. This will provide improved query performance by reducing the frequency that all partitions must be accessed.</font></p>
<p><a href="http://technet.microsoft.com/zh-cn/library/cc966399%28en-us%29.aspx#mainSection"></a><a href="http://technet.microsoft.com/zh-cn/library/cc966399%28en-us%29.aspx#mainSection"><font size="1" face="Arial">Top Of Page</font></a></p>
<h5><font size="1">Aggregation Design Best Practices</font></h5>
<p><font size="1" face="Arial">Good aggregation design is important for achieving good performance when dealing with large amounts of data. Although aggregation design is a complex topic, much of the complexity can be handled automatically by the Storage Design Wizard in SQL Server 2005 Analysis Services.&#160; If you decide to manually design aggregations using some other tool, you’ll need to plan your design much more carefully.&#160; The following best practices contain guidance to help succeed in both scenarios.</font></p>
<h6><font size="1">Consider having aggregations for each partition of significant size</font></h6>
<p><font size="1" face="Arial">Aggregations will generally improve the performance for partitions of non-trivial size. We recommend using aggregations when partition size exceeds 500,000 rows.</font></p>
<h6><font size="1">Do include the granularity attribute of the time dimension in aggregations for measure groups with semi-additive measures</font></h6>
<p><font size="1" face="Arial">Semi-additive measures are calculated at run time by using the granularity attribute of the time dimension.&#160; Therefore, only aggregations that contain this granularity attribute will help performance when calculating the value of semi-additive measures.&#160; </font></p>
<p><font size="1" face="Arial">If you set the AggregationUsage property to Full, the Aggregation Design Wizard and the Usage-Based Optimization Wizard will include this attribute in every aggregation.&#160; If you manually design your aggregations, make sure to include such attributes in every aggregation.</font></p>
<h6><font size="1">Do not build too many aggregations</font></h6>
<p><font size="1" face="Arial">Do not build excessive aggregations. This can adversely affect performance by of increasing search space during queries and increasing the work necessary during processing.&#160; As a rule of thumb, do not build more than 500 aggregations per partition.</font></p>
<h6><font size="1">Consider sharing aggregation designs between partitions of similar size and usage</font></h6>
<p><font size="1" face="Arial">It is usually not necessary or desirable from a management perspective to create separate aggregation designs for every partition.&#160; You generally only need different aggregation designs for partitions that have different sizes or usage patterns. Therefore, similar aggregation designs are not necessary and will add complexity to the database.&#160; </font></p>
<p><font size="1" face="Arial">Partitions that have similar size and usage should share the same aggregation designs. As a rule, three aggregation designs per measure group are generally enough.</font></p>
<h6><font size="1">Consider creating separate aggregation designs for partitions with significantly different size or usage</font></h6>
<p><font size="1" face="Arial">When partitions have significantly different size or usage patterns, it is generally better to create separate aggregation designs and customize the design appropriately.&#160; For example, it makes sense to create separate partitions for each month of the current year and use the same aggregation design for these partitions. However, you will probably want to create a separate aggregation design for the partition that contains all the data for a past year.&#160; This is better because archived data usually is combined into larger partitions and is accessed less frequently.</font></p>
<p><font size="1" face="Arial">For example, the storage settings for partitions can be managed by using the following guidelines:</font></p>
<p><font size="1" face="Arial">&#160;&#160; Frequently queried partitions -&gt; Use MOLAP with lots of aggregations</font></p>
<p><font size="1" face="Arial">&#160;&#160; Periodically queried partitions -&gt; Use MOLAP with less or no aggregations</font></p>
<p><font size="1" face="Arial">&#160;&#160; Rarely queried partitions -&gt; Use ROLAP with no aggregations</font></p>
<h6><font size="1">Do use a lower performance gain with regular aggregation design and a higher performance gain with usage-based optimization</font></h6>
<p><font size="1" face="Arial">When you design generic aggregations, you should target a lower performance gain (20-30%).&#160; When you design aggregations using the Usage-Based Optimization Wizard, you should target a higher performance gain (70-80%), because these aggregations are more specific to actual use.</font></p>
<h6><font size="1">Consider setting AggregationUsage to Unrestricted on high-use attributes that are not the key of a dimension and not in a hierarchy</font></h6>
<p><font size="1" face="Arial">By default, the aggregation design algorithm considers only key attributes and attributes in natural hierarchies for inclusion in aggregations.&#160; Although this is usually the best strategy, if you have an attribute that is neither the key attribute nor contained in a hierarchy, but you expect people to group by the attribute or filter on it, you should consider setting AggregationUsage to Unrestricted. When you do this, the aggregation design algorithm will consider the attribute when it designs aggregations.</font></p>
<h6><font size="1">Avoid Setting AggregationUsage to Full on Large Attributes</font></h6>
<p><font size="1" face="Arial">Avoid setting the AggregationUsage property to Full on attributes that have many members. If you use the Aggregation Wizard, this setting may prevent any aggregations from being created, because this setting prevents the wizard from creating aggregations that do not include this attribute. </font></p>
<h6><font size="1">Do set member and row counts accurately for the partition when designing aggregations</font></h6>
<p><font size="1" face="Arial">Although member and row counts do not have to be exact, they should be reasonably accurate because they will be used to evaluate the cost, both in disk size and read time, of aggregations. Moreover, these counts will significantly affect the aggregations chosen by the aggregation design algorithm.&#160; </font></p>
<p><font size="1" face="Arial">You may find that not all members of a dimension exist in a partition, especially when the partition policy is based on the dimension: for example, in time-based partitioning.&#160; When this is true, it is important to provide an accurate approximation of the actual count of members found in the partition.</font></p>
<h6><font size="1">Consider including the granularity attribute of the intermediate dimensions of many-to-many dimensions in aggregations</font></h6>
<p><font size="1" face="Arial">When accessing data using a many-to-many dimension, the server will always use the granularity attribute of the dimension that serves as an intermediate dimension for that many-to-many dimension.&#160; Therefore, only aggregations that contain this granularity attribute will help performance when using many-to-many dimensions.&#160; Aggregations on other attributes of the intermediate dimension can still be useful when the intermediate dimension is used directly, and when the many-to-many dimension is not used in a query.</font></p>
<p><font size="1" face="Arial">If you have multiple dimensions shared between the measure groups in a many-to-many relationship, it is undefined which dimension the server will use as the intermediate dimension. Therefore, you should consider including the granularity attributes of each such potential intermediate dimension in aggregations.</font></p>
<h6><font size="1">Do include in aggregations the granularity attribute of dimensions that contain unary operators or custom rollups </font></h6>
<p><font size="1" face="Arial">Unary operators and custom rollups are calculated at run time from the granularity attribute of the dimension that contains them.&#160; Therefore, only aggregations that contain this granularity attribute will help performance when using dimensions with unary operators or custom rollups.&#160; </font></p>
<p><font size="1" face="Arial">The Aggregation Design Wizard and the Usage-Based Optimization Wizard will automatically include such dimension’s granularity attributes in aggregations.&#160; However, if you manually design aggregations, be sure to include such granularity attributes in every aggregation.</font></p>
<h6><font size="1">Avoid creating aggregations that are larger than one-third the size of the fact data</font></h6>
<p><font size="1" face="Arial">Aggregations this large generally do not help performance.&#160; The Aggregation Design Wizard and Usage-Based Optimization Wizard will apply this rule automatically, but you should monitor the size of aggregations and the size of the fact data when you manually design aggregations.</font></p>
<h6><font size="1">Do remove aggregation designs that are not applied to any partitions</font></h6>
<p><font size="1" face="Arial">Remove any aggregation designs that are not used by any partitions. These can slow metadata operations and offer no benefit.&#160; Removal of unused aggregations is performed automatically when you use the Copy Aggregation Design dialog box in SQL Server Management Studio. Removal of unused aggregations is also automatic in the Aggregation Design Wizard and the Usage-Based Optimization Wizard. However, if you manually create aggregation designs you should review the design when you have finished and remove unnecessary aggregations.</font></p>
<h6><font size="1">Do not create aggregations that contain multiple attributes from the same attribute relationship chain</font></h6>
<p><font size="1" face="Arial">It is redundant to include an attribute in an aggregation if the value of the attribute is implied by an attribute already in the aggregation, because the implied attribute’s value can be calculated from the first attribute.&#160; Also, for a given query, only one of these attributes is of interest in the aggregation.&#160; The best practice is to remove the implied attribute from the aggregation and, optionally, create a new aggregation that contains the implied attribute but not the implying attribute.&#160; The Aggregation Design Wizard and Usage-Based Optimization Wizard will apply this rule automatically, but if you manually design aggregations, you may have to modify your design to remove redundant attributes.</font></p>
<h6><font size="1">Consider including in aggregations only those attributes with rigid relationships to their dimension keys</font></h6>
<p><font size="1"></font><font face="Arial">Aggregations are considered flexible when any attribute included in the aggregation is related, either directly or indirectly, to the key of its dimension through any attribute relationship that has RelationshipType set to Flexible.&#160; Aggregations are also considered flexible when they include a parent-child hierarchy.</font>&#160; Because a flexible aggregation might be dropped during a Process Update of a dimension and will only be recreated when Process Index is performed, a better practice is to create rigid aggregations whenever possible, instead of flexible aggregations.&#160; Sometimes you can achieve this by selecting an attribute closer to the key of the dimension.</p>
<p><font size="1">For example, assume the following chain of relationships, where the notation ==&gt; means a rigid relationship and --&gt; means a flexible relationship:</font></p>
<p><font size="1">&#160;&#160;&#160; Customer ==&gt; City --&gt; Sales Region ==&gt; Country</font></p>
<p><font size="1">Given these relationships, any aggregations that use Sales Region or Country will be flexible, whereas aggregations that use Customer or City may be rigid.&#160; To avoid creating a flexible relationship, you might include City in the aggregation instead of Sales Region.</font></p>

	标签：<a href="http://www.imkevinyang.com/categories/techarticles/businessintelligence" title="BI/数据库" rel="tag">BI/数据库</a>, <a href="http://www.imkevinyang.com/tags/olap" title="OLAP" rel="tag">OLAP</a>, <a href="http://www.imkevinyang.com/tags/%e5%a4%9a%e7%bb%b4%e6%95%b0%e6%8d%ae%e9%9b%86" title="多维数据集" rel="tag">多维数据集</a>, <a href="http://www.imkevinyang.com/tags/%e6%80%a7%e8%83%bd%e4%bc%98%e5%8c%96" title="性能优化" rel="tag">性能优化</a>, <a href="http://www.imkevinyang.com/tags/%e6%80%a7%e8%83%bd%e6%8c%87%e5%8d%97" title="性能指南" rel="tag">性能指南</a>, <a href="http://www.imkevinyang.com/tags/%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5" title="最佳实践" rel="tag">最佳实践</a>, <a href="http://www.imkevinyang.com/tags/%e7%bb%b4%e5%ba%a6%e8%ae%be%e8%ae%a1" title="维度设计" rel="tag">维度设计</a><br />

	<h4 style="background-color:#3B3B3B;border-bottom:2px groove gray;color:#F2F2F2;margin-top:20px;padding:6px 6px 6px 15px;margin:20px 0px 0px 0px">你可能对下面的文章感兴趣</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.imkevinyang.com/2009/04/analysis-services-2005-olap%e8%ae%be%e8%ae%a1%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5.html" title="Analysis Services 2005 OLAP设计最佳实践 (2009/04/02)">Analysis Services 2005 OLAP设计最佳实践</a> </li>
	<li><a href="http://www.imkevinyang.com/2010/04/analysis-services%ef%bc%9a%e4%bd%a0%e5%ba%94%e8%af%a5%e4%bd%bf%e7%94%a8%e5%a4%9a%e5%af%b9%e5%a4%9a%e7%bb%b4%e5%ba%a6%e5%90%97%ef%bc%9f.html" title="Analysis Services：你应该使用多对多维度吗？ (2010/04/12)">Analysis Services：你应该使用多对多维度吗？</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/03/bids%e9%83%a8%e7%bd%b2%e6%97%b6%e5%87%ba%e7%8e%b0%e5%85%83%e6%95%b0%e6%8d%ae%e7%ae%a1%e7%90%86%e5%99%a8%e5%8f%91%e7%94%9f%e9%94%99%e8%af%af.html" title="BIDS部署时出现元数据管理器发生错误 (2009/03/13)">BIDS部署时出现元数据管理器发生错误</a> </li>
	<li><a href="http://www.imkevinyang.com/2009/08/olap%e4%b8%ad%e7%9a%84averageofchildren%e8%81%9a%e5%90%88%e6%96%b9%e5%bc%8f.html" title="OLAP中的AverageOfChildren聚合方式 (2009/08/10)">OLAP中的AverageOfChildren聚合方式</a> </li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.imkevinyang.com/2009/05/analysis-service-2005-olap-best-practice-white-paper.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using disk: enhanced

Served from: www.imkevinyang.com @ 2012-02-09 10:36:44 -->
