﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava--随笔分类-Database</title><link>http://www.blogjava.net/jackstudio/category/16527.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 01 Mar 2007 01:24:00 GMT</lastBuildDate><pubDate>Thu, 01 Mar 2007 01:24:00 GMT</pubDate><ttl>60</ttl><item><title>用SQL SERVER 触发器+作业</title><link>http://www.blogjava.net/jackstudio/archive/2007/01/20/95009.html</link><dc:creator>jackstudio</dc:creator><author>jackstudio</author><pubDate>Fri, 19 Jan 2007 16:48:00 GMT</pubDate><guid>http://www.blogjava.net/jackstudio/archive/2007/01/20/95009.html</guid><wfw:comment>http://www.blogjava.net/jackstudio/comments/95009.html</wfw:comment><comments>http://www.blogjava.net/jackstudio/archive/2007/01/20/95009.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackstudio/comments/commentRss/95009.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackstudio/services/trackbacks/95009.html</trackback:ping><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="82%" border="0">
				<tbody>
						<tr>
								<td height="40"> </td>
						</tr>
						<tr>
								<td>
										<div>前一段给客户做了一个，客户管理系统，系统里设计到了用户的积分问题。</div>
										<div>积分要求是：</div>
										<div>1、用户每消费一元，积分自动加1</div>
										<div>2、从用户注册日开始，每过 一天，用户的积分自动加1。</div>
										<div>3、有特殊原因，管理员可以通过后台给用户加分或减分。</div>
										<div>4、积分可以用来兑奖，兑奖后，自动减去相应的积分。</div>
										<div> </div>
										<div>涉及到4个表：</div>
										<div>1、clubuser用户表，2、consumelog记录用户的消费日志，3、scoreadd管理员为用户加的分。4、prizelog用户兑换过的奖品。</div>
										<div> </div>
										<div>原来的系统实现是：</div>
										<div>要求1：</div>
										<div>他们的消费记录通常是导入的，每次导入后，需要重新计算一下所有用户的积分。</div>
										<div>要求2：</div>
										<div>用APPLICATION保存最后更新用户积分的时间，然后和当天判断，如果是不是当天，就给用户加分，设置APPLICATION为当天，如果是，就不进行操作。</div>
										<div>要求3：</div>
										<div>管理员为某个用户加过分以后，重新计算一下这个用户的积分。</div>
										<div>要求4：</div>
										<div>用户兑奖后，要重新计算一下他的积分。</div>
										<div> </div>
										<div>感觉不是他合理：</div>
										<div>1、导入后计算所有用户的积分不合理，因为，计算积分是很麻烦的，要把用户的消费积分，在网积分，管理员加的积分全部加起来，然后减去消费积分得出来，写入用户表。如果用户多了，消费记录多了，算起来要好几分钟。</div>
										<div>2、每次都要判断APPLCATION的状态，感觉不合理。</div>
										<div>3，4也不是太合理，都要重新计算用户的积分，感觉不合理。</div>
										<div> </div>
										<div>所以做了调整。</div>
										<div> </div>
										<div>1、3、4分别在表，consumelog,scoreadd,prizelog表中写触发器</div>
										<div>2、建立一个作业，在每天0:00:00的时候为所有用户加1分。</div>
										<div> </div>
										<div>实现细节：</div>
										<div>1、表 consumelog 触发器 </div>
										<div>添加记录</div>
										<div>CREATE TRIGGER  addscore ON [dbo].[consumelog] <br />FOR INSERT<br />AS<br />declare @num as int<br />declare @uid as int<br />select @num=cmoney,@uid=userid from [inserted]<br />update clubuser set <a href="mailto:score=score+@num/2"><font color="#004377">score=score+@num/2</font></a> where <a href="mailto:id=@uid"><font color="#004377">id=@uid</font></a></div>
										<div>删除记录</div>
										<div>CREATE TRIGGER decscore ON [dbo].[consumelog] <br />FOR DELETE <br />AS<br />declare @num as int<br />declare @uid as int<br />select @num=cmoney,@uid=userid from [deleteed]<br />update clubuser set <a href="mailto:score=score-@num"><font color="#004377">score=score-@num</font></a> where <a href="mailto:id=@uid"><font color="#004377">id=@uid</font></a><br /></div>
										<div>3、scoreadd触发器</div>
										<div>添加记录</div>
										<div>CREATE TRIGGER  otheraddscore ON [dbo].[scoreadd] <br />FOR INSERT<br />AS<br />declare @num int<br />declare @uid int<br />select @num=score,@uid=userid from [inserted]<br />update clubuser set <a href="mailto:score=score+@num"><font color="#004377">score=score+@num</font></a> where <a href="mailto:id=@uid"><font color="#004377">id=@uid</font></a><br />（这个表不存在删除）</div>
										<div> </div>
										<div>4、prizelog触发器</div>
										<div>添加记录</div>
										<div>CREATE TRIGGER prizedecscore ON [dbo].[prizelog] <br />FOR INSERT<br />AS<br />declare @num int<br />declare @uid int<br />declare @prid int<br />select @prid=prizeid,@uid=userid from [inserted]<br />select @num=Score from prize where <a href="mailto:id=@prid"><font color="#004377">id=@prid</font></a><br />update clubuser set <a href="mailto:score=score-@num"><font color="#004377">score=score-@num</font></a> where <a href="mailto:id=@uid"><font color="#004377">id=@uid</font></a></div>
										<div> </div>
										<div>删除记录</div>
										<div>CREATE TRIGGER prizeaddscore ON [dbo].[prizelog] <br />FOR Delete<br />AS<br />declare @num int<br />declare @uid int<br />declare @prid int<br />select @prid=prizeid,@uid=userid from [deleted]<br />if @@rowcount&gt;0<br /> begin<br />   select @num=score from prize where <a href="mailto:id=@prid"><font color="#004377">id=@prid</font></a><br />   update clubuser set <a href="mailto:score=score+@num"><font color="#004377">score=score+@num</font></a> where <a href="mailto:id=@uid"><font color="#004377">id=@uid</font></a><br /> end</div>
										<div> </div>
										<div>2、作业的建立</div>
										<div>SQL SERVER--》管理--》SQL SERVER代理--》作业--》新建作业</div>
										<div>常规 --名称：”每天添加金色俱乐部会员积分“</div>
										<div>步骤--》新建...--》名称 ”添加分数'--》类型：TSQL--》数据库：你要操作的数据库--》命令：</div>
										<div>update clubuser set score=score+1</div>
										<div>调度 --》名称--》调度类型--》反复出现--》每天1次--&gt;时间：0：00：00</div>
										<img alt="" src="http://storage.msn.com/x1pxOYwqu4SjF6YqO-J-kDM2f7oiuKl1LzRkm8lNt1vAdYXJiH_jSMIxBHBQu6zeJbORFuJODhGe3OxEBqUCMtAUc9qnUjhfkbeSE7Aq30PtaYWrV2wS_ReOvHpAwJgBHXfBmRK6rpVMZhU9xm5Yhpy8A" />
										<div> </div>
										<div>点 确定保存。</div>
										<div> </div>
										<div>在 作业列表中就有一个 作业，名称是 每天添加金色俱乐部会员积分</div>
										<div>启动该作业前要先启动SQL SERVERAGENT，并设置为随系统启动，OK了。</div>
										<img alt="" src="http://storage.msn.com/x1pxOYwqu4SjF6YqO-J-kDM2f7oiuKl1LzRkm8lNt1vAdZnYiqMrk3Y1h1tb_gkrFvZCLSXkuhbcddNLu1qo30zAcX8oRV55Duds8VRnWxjAC6_cndMzGBDFXJC2igbMRHQTtWol7kKX0d_9IbvxpgViQ" />
										<div> </div>
										<div>这样做以后，只需要添加消费记录，加分记录，领取奖品的记录就可以了，不用每次操作都要考虑分数了。</div>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/jackstudio/aggbug/95009.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackstudio/" target="_blank">jackstudio</a> 2007-01-20 00:48 <a href="http://www.blogjava.net/jackstudio/archive/2007/01/20/95009.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于数据库优化</title><link>http://www.blogjava.net/jackstudio/archive/2006/10/23/76763.html</link><dc:creator>jackstudio</dc:creator><author>jackstudio</author><pubDate>Mon, 23 Oct 2006 07:23:00 GMT</pubDate><guid>http://www.blogjava.net/jackstudio/archive/2006/10/23/76763.html</guid><wfw:comment>http://www.blogjava.net/jackstudio/comments/76763.html</wfw:comment><comments>http://www.blogjava.net/jackstudio/archive/2006/10/23/76763.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackstudio/comments/commentRss/76763.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackstudio/services/trackbacks/76763.html</trackback:ping><description><![CDATA[
		<p>大家都在讨论关于数据库优化方面的东东，刚好参与开发了一个数据仓库方面的项目，以下的一点东西算是数据库优化方面的学习+实战的一些心得体会了，拿出来大家共享。欢迎批评指正阿！</p>
		<p>SQL语句： <br />是对数据库(数据)进行操作的惟一途径； <br />消耗了70%~90%的数据库资源；独立于程序设计逻辑，相对于对程序源代码的优化，对SQL语句的优化在时间成本和风险上的代价都很低； <br />可以有不同的写法；易学，难精通。</p>
		<p>SQL优化： <br />固定的SQL书写习惯，相同的查询尽量保持相同，存储过程的效率较高。 <br />应该编写与其格式一致的语句，包括字母的大小写、标点符号、换行的位置等都要一致</p>
		<p>ORACLE优化器： <br />在任何可能的时候都会对表达式进行评估，并且把特定的语法结构转换成等价的结构，这么做的原因是 <br />要么结果表达式能够比源表达式具有更快的速度 <br />要么源表达式只是结果表达式的一个等价语义结构 <br />不同的SQL结构有时具有同样的操作（例如：= ANY (subquery) and IN (subquery)），ORACLE会把他们映射到一个单一的语义结构。</p>
		<p>1 常量优化： <br />常量的计算是在语句被优化时一次性完成，而不是在每次执行时。下面是检索月薪大于2000的的表达式： <br />sal &gt; 24000/12 <br />sal &gt; 2000 <br />sal*12 &gt; 24000 <br />如果SQL语句包括第一种情况，优化器会简单地把它转变成第二种。 <br />优化器不会简化跨越比较符的表达式，例如第三条语句，鉴于此，应尽量写用常量跟字段比较检索的表达式，而不要将字段置于表达式当中。否则没有办法优化，比如如果sal上有索引，第一和第二就可以使用，第三就难以使用。</p>
		<p>2 操作符优化： <br />优化器把使用LIKE操作符和一个没有通配符的表达式组成的检索表达式转换为一个“=”操作符表达式。 <br />例如：优化器会把表达式ename LIKE 'SMITH'转换为ename = 'SMITH' <br />优化器只能转换涉及到可变长数据类型的表达式，前一个例子中，如果ENAME字段的类型是CHAR(10)， 那么优化器将不做任何转换。 <br />一般来讲LIKE比较难以优化。</p>
		<p>其中： <br />~~ IN 操作符优化： <br />优化器把使用IN比较符的检索表达式替换为等价的使用“=”和“OR”操作符的检索表达式。 <br />例如，优化器会把表达式ename IN ('SMITH','KING','JONES')替换为 <br />ename = 'SMITH' OR ename = 'KING' OR ename = 'JONES‘</p>
		<p>~~ ANY和SOME 操作符优化: <br />优化器将跟随值列表的ANY和SOME检索条件用等价的同等操作符和“OR”组成的表达式替换。 <br />例如，优化器将如下所示的第一条语句用第二条语句替换： <br />sal &gt; ANY (:first_sal, :second_sal) <br />sal &gt; :first_sal OR sal &gt; :second_sal <br />优化器将跟随子查询的ANY和SOME检索条件转换成由“EXISTS”和一个相应的子查询组成的检索表达式。 <br />例如，优化器将如下所示的第一条语句用第二条语句替换： <br />x &gt; ANY (SELECT sal FROM emp WHERE job = 'ANALYST') <br />EXISTS (SELECT sal FROM emp WHERE job = 'ANALYST' AND x &gt; sal)</p>
		<p>~~ ALL操作符优化: <br />优化器将跟随值列表的ALL操作符用等价的“=”和“AND”组成的表达式替换。例如： <br />sal &gt; ALL (:first_sal, :second_sal)表达式会被替换为： <br />sal &gt; :first_sal AND sal &gt; :second_sal <br />对于跟随子查询的ALL表达式，优化器用ANY和另外一个合适的比较符组成的表达式替换。例如 <br />x &gt; ALL (SELECT sal FROM emp WHERE deptno = 10) 替换为： <br />NOT (x &lt;= ANY (SELECT sal FROM emp WHERE deptno = 10)) <br />接下来优化器会把第二个表达式适用ANY表达式的转换规则转换为下面的表达式： <br />NOT EXISTS (SELECT sal FROM emp WHERE deptno = 10 AND x &lt;= sal)</p>
		<p>~~ BETWEEN 操作符优化: <br />优化器总是用“&gt;=”和“&lt;=”比较符来等价的代替BETWEEN操作符。 <br />例如：优化器会把表达式sal BETWEEN 2000 AND 3000用sal &gt;= 2000 AND sal &lt;= 3000来代替。</p>
		<p>~~ NOT 操作符优化: <br />优化器总是试图简化检索条件以消除“NOT”逻辑操作符的影响，这将涉及到“NOT”操作符的消除以及代以相应的比较运算符。 <br />例如，优化器将下面的第一条语句用第二条语句代替： <br />NOT deptno = (SELECT deptno FROM emp WHERE ename = 'TAYLOR') <br />deptno &lt;&gt; (SELECT deptno FROM emp WHERE ename = 'TAYLOR') <br />通常情况下一个含有NOT操作符的语句有很多不同的写法，优化器的转换原则是使“NOT”操作符后边的子句尽可能的简单，即使可能会使结果表达式包含了更多的“NOT”操作符。 <br />例如，优化器将如下所示的第一条语句用第二条语句代替： <br />NOT (sal &lt; 1000 OR comm IS NULL) <br />NOT sal &lt; 1000 AND comm IS NOT NULL sal &gt;= 1000 AND comm IS NOT NULL</p>
		<p>如何编写高效的SQL: <br />当然要考虑sql常量的优化和操作符的优化啦，另外，还需要：</p>
		<p>1 合理的索引设计： <br />例：表record有620000行，试看在不同的索引下，下面几个SQL的运行情况： <br />语句A <br />SELECT count(*) FROM record <br />WHERE date &gt;'19991201' and date &lt; '19991214‘ and amount &gt;2000</p>
		<p>语句B <br />SELECT count(*) FROM record <br />WHERE date &gt;'19990901' and place IN ('BJ','SH')</p>
		<p>语句C <br />SELECT date,sum(amount) FROM record <br />group by date <br />1 在date上建有一个非聚集索引 <br />A：(25秒) <br />B：(27秒) <br />C：(55秒) <br />分析： <br />date上有大量的重复值，在非聚集索引下，数据在物理上随机存放在数据页上，在范围查找时，必须执行一次表扫描才能找到这一范围内的全部行。 <br />2 在date上的一个聚集索引 <br />A：（14秒） <br />B：（14秒） <br />C：（28秒） <br />分析： <br />在聚集索引下，数据在物理上按顺序在数据页上，重复值也排列在一起，因而在范围查找时，可以先找到这个范围的起末点，且只在这个范围内扫描数据页，避免了大范围扫描，提高了查询速度。 <br />3 在place，date，amount上的组合索引 <br />A：（26秒） <br />C：（27秒） <br />B：（&lt; 1秒） <br />分析： <br />这是一个不很合理的组合索引，因为它的前导列是place，第一和第二条SQL没有引用place，因此也没有利用上索引；第三个SQL使用了place，且引用的所有列都包含在组合索引中，形成了索引覆盖，所以它的速度是非常快的。 <br />4 在date，place，amount上的组合索引 <br />A： (&lt; 1秒) <br />B：（&lt; 1秒） <br />C：（11秒） <br />分析： <br />这是一个合理的组合索引。它将date作为前导列，使每个SQL都可以利用索引，并且在第一和第三个SQL中形成了索引覆盖，因而性能达到了最优。</p>
		<p>总结1 <br />缺省情况下建立的索引是非聚集索引，但有时它并不是最佳的；合理的索引设计要建立在对各种查询的分析和预测上。一般来说： <br />有大量重复值、且经常有范围查询（between, &gt;,&lt; ，&gt;=,&lt; =）和order by、group by发生的列，考虑建立聚集索引； <br />经 常同时存取多列，且每列都含有重复值可考虑建立组合索引；在条件表达式中经常用到的不同值较多的列上建立检索，在不同值少的列上不要建立索引。比如在雇员 表的“性别”列上只有“男”与“女”两个不同值，因此就无必要建立索引。如果建立索引不但不会提高查询效率，反而会严重降低更新速度。 <br />组合索引要尽量使关键查询形成索引覆盖，其前导列一定是使用最频繁的列。</p>
		<p>2 避免使用不兼容的数据类型： <br />例如float和INt、char和varchar、bINary和varbINary是不兼容的。数据类型的不兼容可能使优化器无法执行一些本来可以进行的优化操作。例如: <br />SELECT name FROM employee WHERE salary ＞ 60000 <br />在这条语句中,如salary字段是money型的,则优化器很难对其进行优化,因为60000是个整型数。我们应当在编程时将整型转化成为钱币型,而不要等到运行时转化。</p>
		<p>3 IS NULL 与IS NOT NULL： <br />不 能用null作索引，任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下，只要这些列中有一列含有null，该列就会从索引中排 除。也就是说如果某列存在空值，即使对该列建索引也不会提高性能。任何在WHERE子句中使用is null或is not null的语句优化器是不允 许使用索引的。</p>
		<p>4 IN和EXISTS： <br />EXISTS要远比IN的效率高。里面关系到full table scan和range scan。几乎将所有的IN操作符子查询改写为使用EXISTS的子查询。 <br />例子： <br />语句1 <br />SELECT dname, deptno FROM dept <br />WHERE deptno NOT IN <br />(SELECT deptno FROM emp); <br />语句2 <br />SELECT dname, deptno FROM dept <br />WHERE NOT EXISTS <br />(SELECT deptno FROM emp <br />WHERE dept.deptno = emp.deptno); <br />明显的，2要比1的执行性能好很多 <br />因为1中对emp进行了full table scan,这是很浪费时间的操作。而且1中没有用到emp的INdex， <br />因为没有WHERE子句。而2中的语句对emp进行的是range scan。</p>
		<p>5 IN、OR子句常会使用工作表，使索引失效： <br />如果不产生大量重复值，可以考虑把子句拆开。拆开的子句中应该包含索引。</p>
		<p>6 避免或简化排序： <br />应当简化或避免对大型表进行重复的排序。当能够利用索引自动以适当的次序产生输出时，优化器就避免了排序的步骤。以下是一些影响因素： <br />索引中不包括一个或几个待排序的列； <br />group by或order by子句中列的次序与索引的次序不一样； <br />排序的列来自不同的表。 <br />为了避免不必要的排序，就要正确地增建索引，合理地合并数据库表（尽管有时可能影响表的规范化，但相对于效率的提高是值得的）。如果排序不可避免，那么应当试图简化它，如缩小排序的列的范围等。</p>
		<p>7 消除对大型表行数据的顺序存取： <br />在 嵌套查询中，对表的顺序存取对查询效率可能产生致命的影响。比如采用顺序存取策略，一个嵌套3层的查询，如果每层都查询1000行，那么这个查询就要查询 10亿行数据。避免这种情况的主要方法就是对连接的列进行索引。例如，两个表：学生表（学号、姓名、年龄??）和选课表（学号、课程号、成绩）。如果两个 表要做连接，就要在“学号”这个连接字段上建立索引。 <br />还可以使用并集来避免顺序存取。尽管在所有的检查列上都有索引，但某些形式的WHERE子句强迫优化器使用顺序存取。下面的查询将强迫对orders表执行顺序操作： <br />SELECT ＊ FROM orders WHERE (customer_num=104 AND order_num&gt;1001) OR order_num=1008 <br />虽然在customer_num和order_num上建有索引，但是在上面的语句中优化器还是使用顺序存取路径扫描整个表。因为这个语句要检索的是分离的行的集合，所以应该改为如下语句： <br />SELECT ＊ FROM orders WHERE customer_num=104 AND order_num&gt;1001 <br />UNION <br />SELECT ＊ FROM orders WHERE order_num=1008 <br />这样就能利用索引路径处理查询。</p>
		<p>8 避免相关子查询： <br />一个列的标签同时在主查询和WHERE子句中的查询中出现，那么很可能当主查询中的列值改变之后，子查询必须重新查询一次。查询嵌套层次越多，效率越低，因此应当尽量避免子查询。如果子查询不可避免，那么要在子查询中过滤掉尽可能多的行。</p>
		<p>9 避免困难的正规表达式： <br />MATCHES和LIKE关键字支持通配符匹配，技术上叫正规表达式。但这种匹配特别耗费时间。例如：SELECT ＊ FROM customer WHERE zipcode LIKE “98_ _ _” <br />即使在zipcode字段上建立了索引，在这种情况下也还是采用顺序扫描的方式。如果把语句改为SELECT ＊ FROM customer WHERE zipcode &gt;“98000”，在执行查询时就会利用索引来查询，显然会大大提高速度。 <br />另外，还要避免非开始的子串。例如语句：SELECT ＊ FROM customer WHERE zipcode[2，3] &gt;“80”，在WHERE子句中采用了非开始子串，因而这个语句也不会使用索引。</p>
		<p>10 不充份的连接条件： <br />例：表card有7896行，在card_no上有一个非聚集索引，表account有191122行，在account_no上有一个非聚集索引，试看在不同的表连接条件下，两个SQL的执行情况： <br />SELECT sum(a.amount) FROM account a,card b WHERE a.card_no = b.card_no <br />（20秒） <br />将SQL改为： <br />SELECT sum(a.amount) FROM account a,card b WHERE a.card_no = b.card_no and a.account_no=b.account_no <br />（&lt; 1秒） <br />分析： <br />在第一个连接条件下，最佳查询方案是将account作外层表，card作内层表，利用card上的索引，其I/O次数可由以下公式估算为： <br />外层表account上的22541页+（外层表account的191122行*内层表card上对应外层表第一行所要查找的3页）=595907次I/O <br />在第二个连接条件下，最佳查询方案是将card作外层表，account作内层表，利用account上的索引，其I/O次数可由以下公式估算为： <br />外层表card上的1944页+（外层表card的7896行*内层表account上对应外层表每一行所要查找的4页）= 33528次I/O <br />可见，只有充份的连接条件，真正的最佳方案才会被执行。 <br />多表操作在被实际执行前，查询优化器会根据连接条件，列出几组可能的连接方案并从中找出系统开销最小的最佳方案。连接条件要充份考虑带有索引的表、行数多的表；内外表的选择可由公式：外层表中的匹配行数*内层表中每一次查找的次数确定，乘积最小为最佳方案。 <br />不可优化的WHERE子句 <br />例1 <br />下列SQL条件语句中的列都建有恰当的索引，但执行速度却非常慢： <br />SELECT * FROM record WHERE substrINg(card_no,1,4)='5378' <br />(13秒) <br />SELECT * FROM record WHERE amount/30&lt; 1000 <br />（11秒） <br />SELECT * FROM record WHERE convert(char(10),date,112)='19991201' <br />（10秒） <br />分析： <br />WHERE子句中对列的任何操作结果都是在SQL运行时逐列计算得到的，因此它不得不进行表搜索，而没有使用该列上面的索引；如果这些结果在查询编译时就能得到，那么就可以被SQL优化器优化，使用索引，避免表搜索，因此将SQL重写成下面这样： <br />SELECT * FROM record WHERE card_no like '5378%' <br />（&lt; 1秒） <br />SELECT * FROM record WHERE amount&lt; 1000*30 <br />（&lt; 1秒） <br />SELECT * FROM record WHERE date= '1999/12/01' <br />（&lt; 1秒）</p>
		<p>11 存储过程中，采用临时表优化查询： <br />例 <br />1．从parven表中按vendor_num的次序读数据： <br />SELECT part_num，vendor_num，price FROM parven ORDER BY vendor_num <br />INTO temp pv_by_vn <br />这个语句顺序读parven（50页），写一个临时表（50页），并排序。假定排序的开销为200页，总共是300页。 <br />2．把临时表和vendor表连接，把结果输出到一个临时表，并按part_num排序： <br />SELECT pv_by_vn，＊ vendor.vendor_num FROM pv_by_vn，vendor <br />WHERE pv_by_vn.vendor_num=vendor.vendor_num <br />ORDER BY pv_by_vn.part_num <br />INTO TMP pvvn_by_pn <br />DROP TABLE pv_by_vn <br />这 个查询读取pv_by_vn(50页)，它通过索引存取vendor表1.5万次，但由于按vendor_num次序排列，实际上只是通过索引顺序地读 vendor表（40＋2=42页），输出的表每页约95行，共160页。写并存取这些页引发5＊160=800次的读写，索引共读写892页。 <br />3．把输出和part连接得到最后的结果： <br />SELECT pvvn_by_pn.＊，part.part_desc FROM pvvn_by_pn，part <br />WHERE pvvn_by_pn.part_num=part.part_num <br />DROP TABLE pvvn_by_pn <br />这样，查询顺序地读pvvn_by_pn(160页)，通过索引读part表1.5万次，由于建有索引，所以实际上进行1772次磁盘读写，优化比例为30∶1。</p>
		<p>好了，搞定。 <br />其实sql的优化，各种数据库之间都是互通的<br /><br /><br /></p>
		<p>影响SQL server性能的关键三个方面(转贴)</p>
		<p>关键词：Sql Server</p>
		<p>转贴自:http://202.200.129.193/ <br />1 逻辑数据库和表的设计 <br />数据库的逻辑设计、包括表与表之间的关系是优化关系型数据库性能的核心。一个好的逻辑数据库设计可以为</p>
		<p>优化数据库和应用程序打下良好的基础。</p>
		<p>标准化的数据库逻辑设计包括用多的、有相互关系的窄表来代替很多列的长数据表。下面是一些使用标准化</p>
		<p>表的一些好处。</p>
		<p>A:由于表窄，因此可以使排序和建立索引更为迅速</p>
		<p>B:由于多表，所以多镞的索引成为可能</p>
		<p>C:更窄更紧凑的索引</p>
		<p>D:每个表中可以有少一些的索引，因此可以提高insert update delete等的速度，因为这些操作在索引</p>
		<p>多的情况下会对系统性能产生很大的影响</p>
		<p>E:更少的空值和更少的多余值，增加了数据库的紧凑性</p>
		<p>由于标准化，所以会增加了在获取数据时引用表的数目和其间的连接关系的复杂性。太多的表和复杂的连接关系会降低服务器的性能，因此在这两者之间需要综合考虑。 <br />定义具有相关关系的主键和外来键时应该注意的事项主要是：用于连接多表的主键和参考的键要有相同的数据类型。</p>
		<p>2 索引的设计 <br />A:尽量避免表扫描 <br />检查你的查询语句的where子句，因为这是优化器重要关注的地方。包含在where里面的每一列（column)都是可能的侯选索引，为能达到最优的性能，考虑在下面给出的例子：对于在where子句中给出了column1这个列。 <br />下面的两个条件可以提高索引的优化查询性能！ <br />第一：在表中的column1列上有一个单索引 <br />第二：在表中有多索引，但是column1是第一个索引的列 <br />避免定义多索引而column1是第二个或后面的索引，这样的索引不能优化服务器性能 <br />例如：下面的例子用了pubs数据库。 <br />SELECT au_id, au_lname, au_fname FROM authors <br />WHERE au_lname = 'White' <br />按下面几个列上建立的索引将会是对优化器有用的索引 <br />?au_lname <br />?au_lname, au_fname <br />而在下面几个列上建立的索引将不会对优化器起到好的作用 <br />?au_address <br />?au_fname, au_lname <br />考虑使用窄的索引在一个或两个列上，窄索引比多索引和复合索引更能有效。用窄的索引，在每一页上 <br />将会有更多的行和更少的索引级别（相对与多索引和复合索引而言），这将推进系统性能。 <br />对于多列索引，SQL Server维持一个在所有列的索引上的密度统计（用于联合）和在第一个索引上的 <br />histogram（柱状图）统计。根据统计结果，如果在复合索引上的第一个索引很少被选择使用，那么优化器对很多查询请求将不会使用索引。 <br />有用的索引会提高select语句的性能，包括insert,uodate,delete。 <br />但是，由于改变一个表的内容，将会影响索引。每一个insert,update,delete语句将会使性能下降一些。实验表明，不要在一个单表上用大量的索引，不要在共享的列上（指在多表中用了参考约束）使用重叠的索引。 <br />在某一列上检查唯一的数据的个数，比较它与表中数据的行数做一个比较。这就是数据的选择性，这比较结果将会帮助你决定是否将某一列作为侯选的索引列，如果需要，建哪一种索引。你可以用下面的查询语句返回某一列的不同值的数目。 <br />select count(distinct cloumn_name) from table_name <br />假设column_name是一个10000行的表，则看column_name返回值来决定是否应该使用，及应该使用什么索引。 <br />Unique values Index</p>
		<p>5000 Nonclustered index <br />20 Clustered index <br />3 No index</p>
		<p>镞索引和非镞索引的选择</p>
		<p>&lt;1:&gt;镞索引是行的物理顺序和索引的顺序是一致的。页级，低层等索引的各个级别上都包含实际的数据页。一个表只能是有一个镞索引。由于update,delete语句要求相对多一些的读操作，因此镞索引常常能加速这样的操作。在至少有一个索引的表中，你应该有一个镞索引。 <br />在下面的几个情况下，你可以考虑用镞索引： <br />例如： 某列包括的不同值的个数是有限的（但是不是极少的） <br />顾客表的州名列有50个左右的不同州名的缩写值，可以使用镞索引。 <br />例如： 对返回一定范围内值的列可以使用镞索引，比如用between,&gt;,&gt;=,&lt;,&lt;=等等来对列进行操作的列上。 <br />select * from sales where ord_date between '5/1/93' and '6/1/93' <br />例如： 对查询时返回大量结果的列可以使用镞索引。 <br />SELECT * FROM phonebook WHERE last_name = 'Smith'</p>
		<p>当有大量的行正在被插入表中时，要避免在本表一个自然增长（例如，identity列）的列上建立镞索引。如果你建立了镞的索引，那么insert的性能就会大大降低。因为每一个插入的行必须到表的最后，表的最后一个数据页。 <br />当一个数据正在被插入（这时这个数据页是被锁定的），所有的其他插入行必须等待直到当前的插入已经结束。 <br />一个索引的叶级页中包括实际的数据页，并且在硬盘上的数据页的次序是跟镞索引的逻辑次序一样的。</p>
		<p>&lt;2:&gt;一个非镞的索引就是行的物理次序与索引的次序是不同的。一个非镞索引的叶级包含了指向行数据页的指针。 <br />在一个表中可以有多个非镞索引，你可以在以下几个情况下考虑使用非镞索引。 <br />在有很多不同值的列上可以考虑使用非镞索引 <br />例如：一个part_id列在一个part表中 <br />select * from employee where emp_id = 'pcm9809f' <br />查询语句中用order by 子句的列上可以考虑使用镞索引</p>
		<p>3 查询语句的设计</p>
		<p>SQL Server优化器通过分析查询语句，自动对查询进行优化并决定最有效的执行方案。优化器分析查询语句来决定那个子句可以被优化，并针对可以被优化查询的子句来选择有用的索引。最后优化器比较所有可能的执行方案并选择最有效的一个方案出来。 <br />在执行一个查询时，用一个where子句来限制必须处理的行数，除非完全需要，否则应该避免在一个表中无限制地读并处理所有的行。 <br />例如下面的例子， <br />select qty from sales where stor_id=7131 <br />是很有效的比下面这个无限制的查询 <br />select qty from sales <br />避免给客户的最后数据选择返回大量的结果集。允许SQL Server运行满足它目的的函数限制结果集的大小是更有效的。 <br />这能减少网络I/O并能提高多用户的相关并发时的应用程序性能。因为优化器关注的焦点就是where子句的查询，以利用有用的索引。在表中的每一个索引都可能成为包括在where子句中的侯选索引。为了最好的性能可以遵照下面的用于一个给定列column1的索引。 <br />第一：在表中的column1列上有一个单索引 <br />第二：在表中有多索引，但是column1是第一个索引的列不要在where子句中使用没有column1列索引的查询语句，并避免在where子句用一个多索引的非第一个索引的索引。 <br />这时多索引是没有用的。 <br />For example, given a multicolumn index on the au_lname, au_fname columns of the authors table in <br />the pubs database, <br />下面这个query语句利用了au_lname上的索引 <br />SELECT au_id, au_lname, au_fname FROM authors <br />WHERE au_lname = 'White' <br />AND au_fname = 'Johnson' <br />SELECT au_id, au_lname, au_fname FROM authors <br />WHERE au_lname = 'White' <br />下面这个查询没有利用索引，因为他使用了多索引的非第一个索引的索引 <br />SELECT au_id, au_lname, au_fname FROM authors <br />WHERE au_fname = 'Johnson'</p>
		<p>
				<br />
				<br />
		</p>
<img src ="http://www.blogjava.net/jackstudio/aggbug/76763.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackstudio/" target="_blank">jackstudio</a> 2006-10-23 15:23 <a href="http://www.blogjava.net/jackstudio/archive/2006/10/23/76763.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一条sql语句删除表中所有除ID 不同之外的记录，只留一条。</title><link>http://www.blogjava.net/jackstudio/archive/2006/10/18/75983.html</link><dc:creator>jackstudio</dc:creator><author>jackstudio</author><pubDate>Wed, 18 Oct 2006 09:04:00 GMT</pubDate><guid>http://www.blogjava.net/jackstudio/archive/2006/10/18/75983.html</guid><wfw:comment>http://www.blogjava.net/jackstudio/comments/75983.html</wfw:comment><comments>http://www.blogjava.net/jackstudio/archive/2006/10/18/75983.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jackstudio/comments/commentRss/75983.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jackstudio/services/trackbacks/75983.html</trackback:ping><description><![CDATA[
		<p>表：<br />CREATE TABLE Company_Info<br />(<br />   id  smallint IDENTITY(1,1) ,<br />   username varchar(50) null,<br />   password varchar(50) null,<br />   PRIMARY KEY(id) <br />)<br /><br />思路<br /></p>
		<p>------------显示哪些人相同，相同的数量是多少？</p>
		<p>select convert(int,SQRT(count(*))) as countU ,a.username from Company_Info a left join Company_Info b on </p>
		<p>a.username=b.username and a.password=b.password</p>
		<p>group by a.username having SQRT(count(*)) &gt;1</p>
		<p> </p>
		<p>----------取出所有相同的记录到一个表MyRepeat</p>
		<p>
				<br />select c.* into MyRepeat from Company_Info c where c.username in(<br />select a.username from Company_Info a left join Company_Info b on <br />a.username=b.username and a.password=b.password<br />group by a.username having SQRT(count(*)) &gt;1)</p>
		<p> </p>
		<p> </p>
		<p>-----------在表MyRepeat中找出每个相同记录的除最大id之外</p>
		<p>
				<br />select a.id from MyRepeat a where id not in(select max(b.id) from MyRepeat b group by b.username)--得出所有需要删除的id<br /><br />-----------<br />最后得出<br /><br /></p>
		<p>delete Company_Info where id in (select h.id from (select c.* from Company_Info c where c.username in(select a.username from Company_Info a left join Company_Info b on a.username=b.username and a.password=b.password group by a.username having SQRT(count(*)) &gt;1) ) h where h.id not in( select max(l.id) from (select k.id,username from (select f.* from Company_Info f where f.username in(select g.username from Company_Info g left join Company_Info o on g.username=o.username and g.password=o.password group by g.username having SQRT(count(*)) &gt;1)) k ) l group by l.username))</p>
		<p> </p>
		<p>
				<br />
				<br />
				<br /> </p>
<img src ="http://www.blogjava.net/jackstudio/aggbug/75983.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jackstudio/" target="_blank">jackstudio</a> 2006-10-18 17:04 <a href="http://www.blogjava.net/jackstudio/archive/2006/10/18/75983.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>