手机浏览 RSS 2.0 订阅 膘叔的简单人生 , 腾讯云RDS购买 | 超便宜的Vultr , 注册 | 登陆
浏览模式: 标准 | 列表全部文章

联合索引的经典例子

1.SQL需求,统计当天的数据量。

SQL> SELECT count(*) FROM test_union WHERE win_type=1 AND gmt_create >= trunc(sysdate,'dd') and gmt_create <= trunc(sysdate,'dd')+1;

  COUNT(*)
----------
   20063

1 row selected.

2.查看其索引,以gmt_create开头。

sql>create index idx_union on test_union (gmt_create,win_type) tablespace tbs_index compute statistics;

3.查看awr报表的性能,逻辑读很高,达到9700个。

Buffer Gets   Executions  Gets per Exec %Total Time  Time (s) Hash Value
--------------- ---------- -------------- ------ -------- --------- ------
205,157,987    21,236      9,660.9      34.5  6733.21  7568.58 1532799124
Module: java@app12345 (TNS V1-V3)
SELECT count(*) FROM test_union WHERE win_type=1 AND gmt_create >= trunc(sysdate,'dd') and gmt_create <= trunc(sysdate,'dd')+1

因为是只通过索引扫描,当看到返回结果集在2万左右,我们很容易估算出这个sql需要的逻辑读,(gmt_date字段7个字节+win_type字段1个字节+rowid+…)*2万,小于100个,现在很明显是偏高的。
4.调整前我们先去看数据分布。

SQL> select win_type,count(*) from test_union group by win_type;  --按win_type分组
  win_type   count(*)
---------- ----------
         0    8583162
         1    2725424
         2    765237
         3    2080156
         4    2090871
         5    3568682
SQL> select count(*) from test_union where gmt_create >= trunc(sysdate,'dd') and gmt_create <= trunc(sysdate,'dd')+1; --按gmt_create统计,一天数据量在22万左右

  COUNT(*)
----------
     229857

1 row selected.

5.调整索引,改为以win_type开头,为什么要以win_type开头呢?

create index idx_union123 on test_union (win_type,gmt_create) tablespace tbs_index compute statistics;  --新索引

6.查看其执行计划,逻辑读变成了89。

sql>set auto traceonly
sql> select count(*) from test_union
where win_type=1 and gmt_create >= trunc(sysdate,'dd') and gmt_create <= trunc(sysdate,'dd')+1;

Elapsed: 00:00:07.17

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=9)
   1    0   SORT (AGGREGATE)
   2    1     FILTER
   3    2       INDEX (RANGE SCAN) OF 'idx_union123' (NO
          N-UNIQUE) (Cost=7 Card=1 Bytes=9)
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
         89  consistent gets
          0  physical reads
          0  redo size
        493  bytes sent via SQL*Net to client
        655  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

都在说建索引一定要看数据分布,从数据分布来看,一天的的数据(gmt_create)量在22万左右,而win_type的数据量非常 大,win_type为1有300万左右,为什么还要把win_type放在索引的前面呢?抛块砖,希望大家能对联合索引有更深入的理解,希望一起讨论。

--EOF--

帖子下的几个评论也很有意思:

XML/HTML代码
  1.  1.     1棉花糖ONE  
  2.   
  3.     hehe,所以我在itpub上经常建议人家如果是建复合索引的话,把范围查询的谓词尽量放在后面,这样能增加木匠说的有效索引选择度,对oracle执行计划的判断有意义,当然更主要的是这样创建索引确实是减少了索引扫描的范围,不知道楼主的环境还在不在,根据数据来看,这2个字段是相关的,而且楼主恰好查询的是 count(*),可以不扫描表,走复合索引就比较正常,如果是select * from … ,这样很可能就不会选择走索引,就11g以前除了动态采样,加hint,统计信息上应该是搞不对,我测试了11g的扩展列的统计信息,感觉这玩意效果没有想象中的理想  
  4.     Comment on Jan 10th, 2009 at 9:58 am    
  5.  2. 2木匠  
  6.   
  7.     如果没有搞清楚SQL optimizer engine and Run time engine怎么工作,怎么使用composite index,  
  8.     你的观测结果只是表面现象,永远也不知道为什么.  
  9.   
  10.     查看数据分布是对的,  
  11.     但是这种情况是需要寻根问底的. my CA$0.02 + tax, 我的一点建议.  
  12.   
  13.     木匠不辞劳苦,再重复一遍SQL optimizer and runtime engine 是怎么工作的:  
  14.   
  15.     as soon as we have a range scan on a column used somewhere in the  
  16.     middle of an index definition or fail to supply a test on such a column, the predicates on later columns do not restrict the selection of index leaf blocks that we have to examine.  
  17.   
  18.     In this case, the effective index selectivity has to be calculated from the predicate on just the “gmt_create” column. Because the test on “gmt_create” is range-based, the predicates on “win_type” do not restrict the number of index leaf blocks we have to walk.  
  19.   
  20.     关键字: effective index selectivity.  
  21.     Comment on Jan 10th, 2009 at 1:49 am    
  22.  3. 3丁原  
  23.   
  24.     这个案例已经很久了。  
  25.     实际上是没有打算写的,这个例子一直有人在问为什么,问的多了,我干脆就邮件中的内容整理出来,大家 讨论加深印象。  
  26.     我尝试把线上的数据拉下来做测试,发觉太大了根本拉不下来,只能是拼拼凑凑,gmt_create的索引已经drop掉了,部分测试数据可能不那么准确,但是数据还是在范围之内,不会偏差很大。  
  27.   
  28.     逻辑读怎么算?  
  29.     select (7+1+rowid+..)*20000/8192,差不多就是我们要的逻辑读。  
  30.   
  31.     to木匠:cost不一定准确的,我更多的是查看数据分布,结果集,以逻辑读来判断。  
  32.     to棉花糖:回复有审核的,防止很多垃圾广告。  
  33.     Comment on Jan 9th, 2009 at 5:11 pm    
  34.  4. 4carcase  
  35.   
  36.     win_type,gmt_create 扫描的索引块少多了,确定了win_type=1的范围后,再确定了是当天的数据  
  37.     (索引是win_type,gmt_create 排序的,范围扫描马上能定位到当天的数据)也就扫描了2万多就够了 ,速度得到了提升。  
  38.     和  
  39.     gmt_create,win_type 扫描的索引块多了很多,相当于扫描了 gmt_create当天所有的数据了,22万多数据都要扫描一遍,过滤出win_type=1 的数据  
  40.     Comment on Jan 9th, 2009 at 11:05 am    
  41.  5. 5棉花糖ONE  
  42.   
  43.     Your comment is awaiting moderation.  
  44.     到底咋回事啊  
  45.     Comment on Jan 9th, 2009 at 10:45 am    
  46.  6. 6棉花糖ONE  
  47.   
  48.     逻辑读89是不是搞错了  
  49.     Comment on Jan 9th, 2009 at 10:45 am    
  50.  7. 7jlttt  
  51.   
  52.     我们很容易估算出这个sql需要的逻辑读,(gmt_date字段7个字节+win_type字段1个字节+rowid+…)*2万,小于100个  
  53.     (7+1+10+…)×2W 所读的块怎么算出小于100的?  
  54.     Comment on Jan 9th, 2009 at 9:46 am    
  55.  8. 8棉花糖ONE  
  56.   
  57.     to 木匠:  
  58.     cardinality=1可能和9i有关,sysdate包含函数计算的时候,没有直方图的情况下,范围查询的选择度是按5%算的,2个5%*5%  
  59.     Comment on Jan 9th, 2009 at 9:42 am    
  60.  9. 9棉花糖ONE  
  61.   
  62.     如果把范围的放前面,索引的第二个字段只是起到filter的作用,并没有减少索引扫描的块,从索引的成本计算也能看出这一点  
  63.     Comment on Jan 9th, 2009 at 9:36 am    
  64. 10. 10木匠  
  65.   
  66.     对不起,再唠叨一句.  
  67.   
  68.     除了比较cost,还要比较Cardinality, 第二个SQL,index scan这一步的Card=1.  
  69.     但是我觉得index scan这一步的Cardinality应该大于一, 不知道哪里出了问题.  
  70.   
  71.     每一个Oracle版本的Cost and Card会有不同的结果.9.2.0.6 and 10.1.0.4或更高版本会提供更有用的信息.  
  72.   
  73.     (木匠真够粗心大意的, 请包涵)  
  74.     Comment on Jan 9th, 2009 at 2:26 am    
  75. 11. 11木匠  
  76.   
  77.     In this case, the effective index selectivity has to be calculated from the predicate on just the “gmt_create” column. Because the test on “gmt_create” is range-based, the predicates on “win_type” do not restrict the number of index leaf blocks we have to walk.  
  78.   
  79.     照搬老刘(Lewis)的原话, 改一下列名就行了. :)  
  80.   
  81.     上一个评论中的cost 指的是整个SQL(with index scan)的cost.  
  82.   
  83.     另外, 你忘了记录走第一个索引的SQL执行计划,可以比较一下 INDEX (RANGE SCAN) 的 cost.  
  84.   
  85.     INDEX (RANGE SCAN) OF ‘idx_union123′ (NON-UNIQUE) (Cost=7 Card=1 Bytes=9), 我们看到走第二个索引的(index range scan) cost=7.  
  86.     Comment on Jan 9th, 2009 at 2:03 am    
  87. 12. 12木匠  
  88.   
  89.     Q: 为什么还要把win_type放在索引的前面呢?  
  90.     A: leaf_blocks * effective index selectivity  
  91.   
  92.     第一个索引, range scan on gmt_create, first column on index.  
  93.     Because as soon as we have a range scan on a column used somewhere in the  
  94.     middle of an index definition or fail to supply a test on such a column, the predicates on later columns do not restrict the selection of index leaf blocks that we have to examine.  
  95.   
  96.     参考:  
  97.     cost =  
  98.     blevel +  
  99.     ceiling(leaf_blocks * effective index selectivity) +  
  100.     ceiling(clustering_factor * effective table selectivity)  
  101.   
  102.     a well-known guideline for arranging the columns in a multicolumn  
  103.     index. Columns that usually appear with range-based tests should generally appear later in the index than columns that usually appear with equality tests. Unfortunately, changing the column ordering in an index can have other contrary effects, which we will examine in Chapter 5.  
  104.   
  105.     Now you got test case. very well ! ^_^  
  106.   
  107.     Reference: page 74,62,67 of book Cost-Based Oracle Fundamentals  
  108.     Comment on Jan 9th, 2009 at 1:52 am    

Tags: 索引, mysql, 联合索引, 数据库

接口与抽象类【来自博客园】

什么是接口 (interface) ?

接口是方法的抽象,如果不同的类有同样的方法,那么就应该考虑使用接口。
(1)接口是一个行为的规范、协议。其实就是类和类之间的一种协定,一种约束
(2)C#不支持多继承,但是他把这个功能交给接口来实现。
(3)类与类之间的系统资源调用方式不一样,导致他们之间的通信很困难,而接口可以屏蔽掉它们之间的差异,能使他们顺利通信。

什么是抽象类(abstract class)?

1. 抽 象类仅提供一个类型的部分实现。抽象类可以有实例变量,以及一个或多个构造函数。抽象类可以同时有抽象方法和具体方法。一个抽象类不会有实例,这些构造函 数不能被客户端调用来创建实例。一个抽象类的构造函数可以被其子类调用,从而使一个抽象类的所有子类都可以有一些共同的实现,而不同的子类可以在此基础上 有其自己的实现。

2.  抽象类的用途1)  具体类不是用来继承的。 Scott Meyers曾指出,只要有可能,不要丛具体类继承。2)  假设有2个具体类,类A和类B,类B是类A 的子类,那么一个最简单的修改方案是应当建立一个抽象类(或java接口)C,然后让类A和类B成为抽象类C的子类。3)  抽象类应当拥有尽可能多的共同代码。以提高代码的复用率。4)  抽象类应当拥有尽可能少的数据。

 3.  基于抽象类的模式和原则1)  针对抽象编程,不要针对具体编程。2)  尽量使用合成(Composition),而不要使用继承来达到复用的目的。3)  使用摸板方法模式

4.  什么时候应当使用继承复用1)  子类是超类的一个特殊种类,而不是超类的一个角色,也就是要区分”is – a” 和“has-a”两种关系。2)  永远不会出现需要将子类换成另一个子类的情况。如果设计师不是很肯定一个类回不会在将来变成另一个类的子类的话,就不应当把这个类设计成这个超类的子类。 3)  子类具有扩展超类的责任,而不是具有置换掉(Override)或注销掉(Nullify)超类的责任。4)  只有在分类学上有意义时,才可以使用继承,不要丛工具类继承。

抽象方法是必须实现的方法。且只能在抽象类中。

接口与抽象类

一个类可以继承多个接口。。。
一个类只能继承一个抽象类。。。

抽象方法是必须实现的方法。就象动物都要呼吸。但是鱼用鳃呼吸,猪用肺呼吸。
动物类要有呼吸方法。怎么呼吸就是子类的事了。

现在有很多讨论和建议提倡用interface代替abstract类,两者从理论上可以做一般性的混用,但是在实际应用中,他们还是有一定区别的。抽象类一般作为公共的父类为子类的扩展提供基础,这里的扩展包括了属性上和行为上的。而接口一般来说不考虑属性,只考虑方法,使得子类可以自由的填补或者扩展接口所定义的方法,就像JAVA王子所说的事件中的适配器就是一个很好的应用。
用一个简单的例子,比如说一个教师,我们把它作为一个抽象类,有自己的属性,比如说年龄,教育程度,教师编号等等,而教师也是分很多种类的,我们就可以继承教师类而扩展特有的种类属性,而普遍属性已经直接继承了下来。
而接口呢~还是拿教师做例子,教师的行为很多,除了和普通人相同的以外,还有职业相关的行为,比如改考卷,讲课等等,我们把这些行为定义成无body的方 法,作为一个集合,它是一个interface。而教师张三李四的各自行为特点又有不同,那么他们就可以扩展自己的行为body。从这点意义上来说,interface偏重于行为
总之,在许多情况下,接口确实可以代替抽象类,如果你不需要刻意表达属性上的继承的话。

原文:http://www.cnblogs.com/cyc09156/archive/2009/01/09/1372330.html

Tags: 接口, 抽象, interface, abstract

经典格斗游戏《街头霸王4》试玩截图

由CAPCOM负责开发的格斗游戏《街头霸王4》(Street Fighter 4)最新试玩截图公布,本作将承袭系列作传统2D玩法,并采用最新的3D绘图技术,以更华丽的方式重现原作独特的2D绘图风格。PC版发售日期未 定,XBOX360/PS3即将2月17日发售。

另外,CAPCOM透露将推出内含限量非卖版人偶模型(PS3 版为隆,Xbox 360 版为深红毒蛇)、Studio 4C 制作之65分钟高分辨率动画影片(PS3版为BD蓝光影片,Xbox 360 版为专用高分辨率DVD影片,非一般 DVD 影片)、原声配乐 CD、攻略指引手册与独家下载内容的典藏版,定价 79.99美元。

以上内容来自于:http://www.lingaoyi.com/screens/new-street-fighter-4-screenshots/,同时以下图片也来自于该站(我只取了两张与我有关的图片)

更多图片请去该网站查看。。。

大小: 85.45 K
尺寸: 500 x 283
浏览: 1984 次
点击打开新窗口浏览全图

大小: 85.29 K
尺寸: 500 x 283
浏览: 1932 次
点击打开新窗口浏览全图

Tags: game, sf4, classic, gouki, ryu

TP1.5版本中使用smarty模版引擎的技巧

从TP1.5开始,对于其他的模版引擎有了原生支持(不再是以前那种插件机制了)。
本文以使用smarty模版为例作点简单介绍,其他的,可以参考一下View.class.php中的fetch方法可知。

TP的SVN中已经含有smarty模版库,因此当你要使用的时候,只需要在项目的config.php里作一点简单的配置:

PHP代码
  1. 'TMPL_ENGINE_TYPE' => 'smarty',    //这个是设置引擎为smarty  


从2009-01-07下午的SVN版本里,流年为又增加了一个TMPL_ENGINE_CONFIG这个数组,即:

PHP代码
  1. 'TMPL_ENGINE_CONFIG'array(  
  2.         'template_dir' => TMPL_PATH , //这个就是tpl目录了  
  3.         'compile_dir'  => CACHE_PATH . "tplCompile/"//这是我自己设定的,模版编译缓存放在这个目录里  
  4.         'cache_dir'    => CACHE_PATH . "tplCache/",   //如果需要生成页面缓存,这个也是必须的  
  5.         'left_delimiter' => '{',  
  6.         'right_delimiter' => '}',  
  7.         'caching' => false,  
  8.         'force_compile' => true,  
  9.         'compile_check' => true,  
  10. ),  


备注:如果按照我这样的写法,请到cache目录里手动创建tplCompile和tplCache两个目录,否则程序会报错。
报错信息大致为:

XML/HTML代码
  1. Catchable fatal error: Object of class Smarty could not be converted to string in D:\local\htdocs\ThinkPHP\Album\Temp\~runtime.php on line 145  


如果出现这样的报错信息,请先检查这两个目录是否存在

在项目开发的时候,caching 最好设为false,否则你根本看不到效果。

如此设定完毕后,你就可以直接在项目中使用了,下面以Index模块的index方法进行举例:在IndexAction.class.php的index的方法里

PHP代码
  1. $this->assign("test" , "This is a test string");  
  2. $this->display();  

然后到模版里:

XML/HTML代码
  1. {$test} 

就可以看到输出了。不过,这里需要注意的是,如果你$this->display()没有指定文件名,那么默认的模版文件就是default/Index/index.html,这点和原先使用TP默认的模版引擎没有什么区别。
出现问题最大的应该是在include方法里,include的使用方法是:{include file="Public/header.html"},就象我前面所说,smarty的模版路径只指到了tpl目录,但实际上,我们是在默认的default目录下操作,因此正确的写法应该是{include file="default/Public/header.html"}
如果我们写的程序要对应多模版,那么,上面那种直接写死default的方法是不行的,还好,TP为我们留了一个常量:TEMPLATE_NAME,于是我们的写法就可以是现在这样:

XML/HTML代码
  1. {include file="`$smarty.const.TEMPLATE_NAME`/Public/header.html"}  

现在试一下,是否公用目录里的header.html被加载了?

最后再报一个warning。如果是在WINDOWS下面开发并且开启了DEBUG_MODE,那么你在读取模版的时候,页面的Trace信息里,偶尔会出现一个注意:

 

XML/HTML代码
  1. [ 09-01-08 14:36:02 ] 注意:[2] unlink(./Cache/tplCompile/\%%70^706^706C3AFE%%index.html.php) [function.unlink]: No such file or directory core.write_file.php 第 44 行.  


这些信息,可以被忽略掉。模版文件还是会正常的生成和编译的。它只会在第一次生成模版编译文件的时候出现

Tags: thinkphp, smarty, template

MYSQL数据库中取得同一字符串出现的次数

在PHP中,取得一个字符串中某一个字符出现的次数那是相当的简单的呀,方法也有N种,再不济我还可以把这个字符当成分隔标记进行分隔,最后求分隔出来的数组的长度就行了。

但MYSQL不行呀,没有这样的函数,还好,网上很多人给出了方案,我这里贴个最简单的:

原理:(用原始字符串的总长度 减去  将原始字符串中要统计的字符串去除后的字符串长度)再除以 要统计的字符串长度

SQL代码
  1. SELECT ( char_length( 'test' ) - char_length( replace('test''t' , ''))) / (char_length('t'));  
  2. ---- 注:test为原始字符串,t为要统计的字符串  

Tags: mysql, str_count, char_length