oracle 统计索引大小索引的一个小问题

在Oracle中创建索引时要注意的问题 - 中华考试网()
&&当前位置: >
> 文章内容
在Oracle中创建索引时要注意的问题 &&【
】&&[ 日 ]
在Oracle数据库中,创建索引虽然比较简单。但是要合理的创建索引则比较困难了。笔者认为,在创建索引时要做到三个适当,即在适当的表上、适当的列上创建适当数量的索引。虽然这可以通过一句话来概括优化的索引的基本准则,但是要做到这一点的话,需要数据库管理员做出很大的努力。具体的来说,要做到这个三个适当有如下几个要求。  一、 根据表的大小来创建索引。  虽然给表创建索引,可以提高查询的效率。但是数据库管理员需要注意的是,索引也需要一定的开销的。为此并不是说给所有的表都创建索引,那么就可以提高数据库的性能。这个认识是错误的。恰恰相反,如果不管三七二十一,给所有的表都创建了索引,那么其反而会给数据库的性能造成负面的影响。因为此时滥用索引的开销可能已经远远大于由此带来的性能方面的收益。所以笔者认为,数据库管理员首先需要做到,为合适的表来建立索引,而不是为所有的表建立索引。  一般来说,不需要为比较小的表创建索引。如在一个ERP系统的数据库中,department表用来存储企业部门的信息。一般企业的部分也就十几个,最多不会超过一百个。这100条记录对于人来说,可能算是比较多了。但是对于计算机来说,这给他塞塞牙缝都还不够。所以,对类似的小表没有必要建立索引。因为即使建立了索引,其性能也不会得到很大的改善。相反索引建立的开销,如维护成本等等,要比这个要大。也就是说,付出的要比得到的多,显然违反常理。  另外,就是对于超大的表,也不一定要建立索引。有些表虽然比较大,记录数量非常的多。但是此时为这个表建立索引并一定的合适。如系统中有一张表,其主要用来保存数据库中的一些变更信息。往往这些信息只给数据库管理员使用。此时为这张表建立索引的话,反而不合适。因为这张表很少用到,只有在出问题的时候才需要查看。其次其即使查看,需要查询的纪录也不会很多,可能就是最近一周的更新记录等等。对于对于一些超大的表,建立索引有时候往往不能够达到预计的效果。而且在打表上建立索引,其索引的开销要比普通的表大的多。那么到底是否给大表建立索引呢?笔者认为,主要是看两个方面的内容。首先是需要关注一下,在这张大表中经常需要查询的记录数量。一般来说,如果经常需要查询的数据不超过10%到15%的话,那就没有必要为其建立索引的必要。因为此时建立索引的开销可能要比性能的改善大的多。这个比例只是一个经验的数据。如果数据库管理员需要得出一个比较精确的结论,那么就需要进行测试分析。即数据库管理员需要测试一下全表扫描的时间,看看其是否比建立索引后的查询时间要长或者短。如果是长的话,则说明有建立索引的必要。但是如果没有的话,则说明还是全表扫描速度来的快。此时也就没有必要建立索引了。  总之,在考虑是否该为表建立索引时,一般来说小表没有建立索引的必要。而对于打表的话,则需要进行实际情况实际分析。简单一点的,可以根据大致的比率来确定。如果要精确一点的,则可以进行全表扫描性能分析,以判断建立索引后是否真的如预期那样改善了数据库性能。  二、 根据列的特征来创建索引。  列的特点不同,索引创建的效果也不同。数据库管理员需要了解为哪些列创建索引可以起到事倍功半的效果。同时也需要了解为哪些列创建索引反而起到的是事倍功半的效果。这有利于他们了解到底给为怎么样的字段建立索引。  根据笔者的经验,往往为如下特征的列创建索引能够起到比较明显的效果。如对于一些重复内容比较少的列,特别是对于那些定义了唯一约束的列。在这些列上建立索引,往往可以起到非常不错的效果。如对于一些null值的列与非Null值的列混合情况下,如果用户需要经常查询所有的非Null值记录的列,则最好为其设置索引。如果经常需要多表连接查询,在用与连接的列上设置索引可以达到事半功倍的效果。  可见,索引设置的是否恰当,不仅跟数据库设计架构有关,而且还跟企业的经济业务相关。为此,对于一些套装软件,虽然一开始数据库管理员已经做了索引的优化工作。但是随着后来经济数据的增加,这个索引的效果会越来越打折扣。这主要是因为记录的表化影响到了索引优化的效果。所以笔者建议各位数据库管理员,即使采用的是大牌软件公司的套装软件,也需要隔一段时间,如一年,对数据库的索引进行优化。该去掉的去掉,该调整的调整,以提高数据库的性能。  如在数据库中有一张表是用来保存用户信息的。其中有个字段身份证号码,这是一个唯一的字段。在数据库设计时,给这个字段创建了索引。但是当这个数据库投入使用之后,用户不怎么输入用户的身份证号码。而且平时也基本不按这个号码来进行查询。当记录月来月多时,这个身份证号码上的索引字段不但不能够改善数据库的查询性能,反而成了鸡肋。对于这些有很多NULL值的列,而且不会经常查询所有的非NULL值记录的列,数据库管理员要下决心,即使清除这些列上的索引。  所以说索引的优化与调整是一个动态的过程,并不是说数据库设计好之后就不需要经过调整。数据库管理员往往需要根据记录的变化情况,来进行适当的变更。以提高索引的效果。  三、 在一个表上创建多少索引合适?  虽然说,在表上创建索引的数量没有限制,但是决不是越多越好。也就是说,在创建索引这项事情上,1+1〉2往往不成立。有时候,创建索引越多,其可能会得到适得其反的效果。那么在一个表上,到底给创建多少索引合适呢?这个没有一个明确的标准。而是需要数据库管理员根据实际的用途以及数据库中记录的情况,来进行判断。首页 1
········
“全国专业技术人员计算机应用能力考试考前冲刺”丛书是为比较熟悉科目内容,但不熟..
定价:¥25.00
优惠价:¥18.80&&本书以国家人力资源和社会保障部人事考试中心颁布的最新版《全国专业技术人员计算机..
定价:¥25.00
优惠价:¥18.80&&
············
············
         Copyright ©
() All Rights Reserved12176人阅读
ORACLE(10)
一、问题发现
2月16日现场同事发现某个tablespace空间快要耗尽,让我们手工清楚些数据,腾出足够空间,等用户有预算添加磁盘。该问题年前已经处理过一次,我们已经将数据保留期限做了缩减,按道理不会这么快出现磁盘空间耗尽的情况。我猜测可能是自动分区程序没有运行,没有自动删除旧分区,而新数据又不断产生,导致磁盘空间被逐渐耗尽。
看出从开始到16号这段时间分区维护没有执行,导致空间满。
于是通知集成组同事运行自动分区维护程序。
自动分区维护运行后,空间使用率低于80%了。问题解决了。
过了1小时,现场同事又反映采集程序卡住不动了,让我们赶紧核查原因,排除故障,给出故障报告。
二、问题分析
首先想到的是不是哪个表被锁住了。
select * from v$locked_object t1,user_objects t2where t1.object_id=t2.object_id
通过语句查到,确实有很多相关表被锁住了。
继续查是哪些语句锁住了表
select sid,&&&&&& v$session.username 用户名,&&&&&& last_call_et 持续时间,&&&&&& status 状态,&&&&&& LOCKWAIT 等待锁,&&&&&& machine 用户电脑名,&&&&&& logon_time 开始登入时间,&&&&&& sql_textfrom v$session, v$process, v$sqlareawhere paddr = addr&& and sql_hash_value = hash_value && and status = 'ACTIVE'&& and v$session.username is not nullorder by last_call_
发现有个delete语句在执行,该delete语句为:
delete from table1 where column1=? and column2=? and column3=?
看该语句的执行计划,发现是全表扫描,没有走索引。
我们估计是不是索引失效了
select status,T.* from user_indexes Twhere table_name='TABLE1'
发现status='INVALID'失效。
重建该索引:
drop index ......
create index ......
问题解决。
是什么问题导致的索引失效呢?该问题是运行分区维护后发生的,于是把该问题转给了开发自动分区管理的同事了。该问题后续再补充。
三、知识点总结
1.如何判断和确认索引失效?
通过查看user_indexes的status来确定用户索引状态。
分区索引查看DBA_IND_PARTITIONS的status来确定。
2.重建索引的方式有哪些,有什么区别?
1)drop index...和create index
2)alter index idx_name rebuild
3)alter index idx_name rebuild online
a)rebuild会阻塞对基表的DML操作,但不会影响rebuild期间查询对原有索引的使用。b)rebuild的数据源可能是基表,也可能是原索引。取决于基表和原索引的大小,那个小,rebuild时就会用那个作为数据源。
c)rebuild online运行用户在索引重建期间执行DML操作。d)rebuild online的数据源是基表。
3.导致索引失效的原因有哪些?原因:当某些操作导致数据的rowid改变,索引就会完全失效。
那什么时候会导致rowid改变使得索引unuseable或者invalid呢?
一般普通表在在如下3个情况下可以使index unusable1)move 【alter table move】【alter table t02 move tablespace tbs01;】2)sqlldr 【sqlldr ( parallel or direct )append 】【sqlldr direct=y + 主键重复】
3)手动alter index unusable
对分区表,又要分local index和globa index来说1)首先上面的导致普通表上的索引失效的原因对分区表也同样适用.2)对local index在exchange without including indexes的时候也会unusable3)global index在partition mt的时候会导致unusable[除非加上update global indexes]
以下为引用:
1.导致的原因: &&&& 在SQL*LOADER 加载过程中会维护索引,由于数据量比较大,在SQL*LOADER 加载过程中出现异常情况,导致ORACLE 来不及维护索引,导致索引处于失效状态,影响查询和加载。&异常情况主要有:在加载过程中杀掉SQL*LOADER 进程,重启,表空间不够等。
2.& global索引,当global 索引所在表执行alter table 涉及下列操作时,会导至该索引失效:
? ADD PARTITION | SUBPARTITION
? COALESCE PARTITION | SUBPARTITION
? DROP PARTITION | SUBPARTITION
? EXCHANGE PARTITION | SUBPARTITION
? MERGE PARTITION | SUBPARTITION
? MOVE PARTITION | SUBPARTITION
? SPLIT PARTITION | SUBPARTITION
? TRUNCATE PARTITION | SUBPARTITION
因此,建议用户在执行上述操作sql 语句后附加update indexes 子句,oracle 即会自动维护全局索引。
3.&执行alter table 时未指定update indexes 子句:
如果是range/list 分区,其local 索引和global 索引不会受影响;
如果是hash 分区,新加分区及有数据移动的分区的local 索引和glocal 索引会被置为unuseable,
需要重新编译
对于分区表中索引失效要重建索引
select 'alter index '||t.index_name||' rebuild partition '||t.partition_name from user_ind_partitions t where t.index_name='IDX_PART2' &and t.status='unusable'
查出来后,在命令窗口执行。查出来的语句就可以了。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:34302次
排名:千里之外
(1)(5)(5)(2)> 索引失败原因where条件的区分度太小导致索引失败原因:基于cost成本分析(oracle因为走全
索引失败原因where条件的区分度太小导致索引失败原因:基于cost成本分析(oracle因为走全
lixinqiang & &
发布时间: & &
浏览:20 & &
回复:0 & &
悬赏:0.0希赛币
索引失败原因
where 条件的区分度太小导致索引失败&& 原因:基于cost成本分析(oracle因为走全表成本会更小):查询小表,或者返回值大概在10%以上失效原因: 索引失效 1) 没有查询条件,或者查询条件没有建立索引 2) 在查询条件上没有使用引导列 3) 查询的数量是大表的大部分,应该是30%以上。 4) 索引本身失效 5) 查询条件使用函数在索引列上(见12) 6) 对小表查询 7) 提示不使用索引 8) 统计数据不真实 9) CBO计算走索引花费过大的情况。其实也包含了上面的情况,这里指的是表占有的block要比索引小。 10)隐式转换导致索引失效.这一点应当引起重视.也是开发中经常会犯的错误. 由于表的字段tu_mdn定义为varchar2(20), 但在查询时把该字段作为number类型以where条件传给Oracle,这样会导致索引失效. 错误的例子:select * from test where tu_mdn=; 正确的例子:select * from test where tu_mdn=''; 11)对索引列进行运算导致索引失效,我所指的对索引列进行运算包括(+,-,*,/,! 等) 错误的例子:select * from test where id-1=9; 正确的例子:select * from test where id=10; 12)使用Oracle内部函数导致索引失效.对于这样情况应当创建基于函数的索引. 错误的例子:select * from test where round(id)=10; 说明,此时id的索引已经不起作用了 正确的例子:首先建立函数索引, create index test_id_fbi_idx on test(round(id)); 然后 select * from test where round(id)=10; 这时函数索引起作用了 1,$<$ 2,单独的&,&,(有时会用到,有时不会) 3,like "%_" 百分号在前. 4,表没分析. 5,单独引用复合索引里非第一位置的索引列. 6,字符型字段为数字时在where条件里不添加引号. 7,对索引列进行运算.需要建立函数索引. 8,not in ,not exist. 9,当变量采用的是times变量,而表的字段采用的是date变量时.或相反情况。 10, 索引失效。 11,基于cost成本分析(oracle因为走全表成本会更小):查询小表,或者返回值大概在10%以上 12,有时都考虑到了 但就是不走索引,drop了从建试试在 13,B-tree索引 is null不会走,is not null会走,位图索引 is null,is not null 都会走 14,联合索引 is not null 只要在建立的索引列(不分先后)都会走, in null时 必须要和建立索引第一列一起使用,当建立索引第一位置条件是is null 时, 其他建立索引的列可以是is null(但必须在所有列 都满足is null的时候), 或者=一个值;当建立索引的第一位置是=一个值时,其他索引列可以是任何情况(包括is null =一个值), 以上两种情况索引都会走。其他情况不会走。
本问题标题:
本问题地址:
温馨提示:本问题已经关闭,不能解答。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&oracle的索引使用
最近工作要处理一批统计sql,过程中遇到一些问题,在此分享一下
oracle中最常用的索引就两种:B树索引和位图索引,这里就来简单说下这两种索引的使用。
B-树索引在Oracle中是一个通用的索引,在创建索引时它就是默认的索引类型。最多可以包括32列。&
位图索引Oracle为每个唯一键创建一个位图,然后把与键值所关联的ROWID保存为位图。最多可以包括30列。
一般情况下,大多数用户都只创建TYPE为NORMAL的B-树索引,所以对于较低基数的列我们都是不创建索引的,因为B-树索引对查询速度提升不一定会有改善,甚至会增加Insert、Update、Delete命令所消耗的时间。
位图索引在加载表(插入操作)时通常要比B-树索引做得好。通常,位图索引要比一个低基数(很少不同值)上的B-树索引要快3~4倍,但如果新增的值占插入行的70%以上时,B-树索引通常会更快一些。当每条记录都增加一个新值时,B-树索引要比位图索引快3倍。
建议不要在一些联机事务处理(OLTP)应用程序中使用位图索引。B-树索引的索引值中包含ROWID,这样Oracle就可以在行级别上锁定索引。位图索引被存储为压缩的索引值,其中包含了一个范围内的ROWID,因此ORACLE必须针对一个给定值锁定所有范围内的ROWID。这种锁定可能自阿某些DML语句中造成死锁。SELECT语句不会受到这种锁定问题的影响。
位图索引有很多限制:
基于规则的优化器不会考虑位图索引
当执行ATLER
TABLE语句,并修改包含有位图索引的列时,会使位图索引实效
位图索引在索引块中储存了索引键的值;然而,他们并不能用户任何类型的完整性检查
位图索引不能被申明为唯一索引
以上是援引的一些简单概念,下面是我实际工作中总结出来的:
我要做一个查询,涉及两个表t_sym_dict,t_sym_operlog,表结构分别如下:
其中t_sym_operlog的索引如下:
上面基数比较小的三列创建了位图索引
t_sym_dict的索引如下:
查询语句如下:
select (select
c.dict_name
from t_sym_dict c
where c.dict_typeid = 'SYM_CITYINFO'
&&&&&&&&&&
and c.dict_id = t.memo)
分公司,&&&&&&
t.staff_id 工号
& from t_sym_operlog t
&where t.operlog_subtype = '103'
&& and t.obj_type =
'CUSTLINKINFO'
&& and t.memo = '200'
&--& and t.extsys_code = ''
&--& and t.staff_id = ''
&& and t.oper_date
&= to_date('00',
'yyyymmddhh24miss')
&& and t.oper_date
&= to_date('00',
'yyyymmddhh24miss')
-- order by t.memo, t.oper_date
然后就出现了如下奇怪的现象(索引的创建没有问题)
1、索引使用正常
2、下面的看不到oper_date索引的使用
3、下面的看不到t_sym_operlog表的索引使用
尝试的解决的办法:
对数据表做采集,就是analysis
DBMS_STATS.gather_table_stats(ownname =&
'CSID',tabname =& 't_sym_operlog_back');
猜测的导致原因:
当你运用SQL语言,向数据库发布一条查询语句时,ORACLE将伴随产生一个“执行计划”,也就是该语句将通过何种数据搜索方案执行,是通过全表扫描、还是通过索引搜寻等其它方式。搜索方案的选用与ORACLE的优化器息息相关。
SQL语句的执行步骤
   一条SQL语句的处理过程要经过以下几个步骤。
1 语法分析 分析语句的语法是否符合规范,衡量语句中各表达式的意义。
2 语义分析 检查语句中涉及的所有数据库对象是否存在,且用户有相应的权限。
3 视图转换 将涉及视图的查询语句转换为相应的对基表查询语句。
4 表达式转换 将复杂的SQL表达式转换为较简单的等效连接表达式。
5 选择优化器 不同的优化器一般产生不同的“执行计划”
6 选择连接方式 ORACLE有三种连接方式,对多表连接ORACLE可选择适当的连接方式。
7 选择连接顺序 对多表连接ORACLE选择哪一对表先连接,选择这两表中哪个表做为源数据表。
8 选择数据的搜索路径 根据以上条件选择合适的数据搜索路径,如是选用全表搜索还是利用索引或是其他的方式。
9 运行“执行计划”
oracle优化器CBO存在的典型问题:
有时,表明明建有索引,但查询过程显然没有用到相关的索引,导致查询过程耗时漫长,占用资源巨大,问题到底出在哪儿呢?按照以下顺序查找,基本上能发现原因所在。
查找原因的步骤
  首先,我们要确定数据库运行在何种优化模式下,相应的参数是:optimizer_mode。可在svrmgrl中运行“show
parameter optimizer_mode"来查看。ORACLE
V7以来缺省的设置应是"choose",即如果对已分析的表查询的话选择CBO,否则选择RBO。如果该参数设为“rule”,则不论表是否分析过,一概选用RBO,除非在语句中用hint强制。
  其次,检查被索引的列或组合索引的首列是否出现在PL/SQL语句的WHERE子句中,这是“执行计划”能用到相关索引的必要条件。
  第三,看采用了哪种类型的连接方式。ORACLE的共有Sort Merge Join(SMJ)、Hash
Join(HJ)和Nested Loop Join(NL)。在两张表连接,且内表的目标列上建有索引时,只有Nested
Loop才能有效地利用到该索引。SMJ即使相关列上建有索引,最多只能因索引的存在,避免数据排序过程。HJ由于须做HASH运算,索引的存在对数据查询速度几乎没有影响。
  第四,看连接顺序是否允许使用相关索引。假设表emp的deptno列上有索引,表dept的列deptno上无索引,WHERE语句有emp.deptno=dept.deptno条件。在做NL连接时,emp做为外表,先被访问,由于连接机制原因,外表的数据访问方式是全表扫描,emp.deptno上的索引显然是用不上,最多在其上做索引全扫描或索引快速全扫描。
  第五,是否用到系统数据字典表或视图。由于系统数据字典表都未被分析过,可能导致极差的“执行计划”。但是不要擅自对数据字典表做分析,否则可能导致死锁,或系统性能下降。
  第六,索引列是否函数的参数。如是,索引在查询时用不上。
  第七,是否存在潜在的数据类型转换。如将字符型数据与数值型数据比较,ORACLE会自动将字符型用to_number()函数进行转换,从而导致第六种现象的发生。
  第八,是否为表和相关的索引搜集足够的统计数据。对数据经常有增、删、改的表最好定期对表和索引进行分析,可用SQL语句“analyze
table xxxx compute statistics for all
"。ORACLE掌握了充分反映实际的统计数据,才有可能做出正确的选择。
  第九,索引列的选择性不高。
  我们假设典型情况,有表emp,共有一百万行数据,但其中的emp.deptno列,数据只有4种不同的值,如10、20、30、40。虽然emp数据行有很多,ORACLE缺省认定表中列的值是在所有数据行均匀分布的,也就是说每种deptno值各有25万数据行与之对应。假设SQL搜索条件DEPTNO=10,利用deptno列上的索引进行数据搜索效率,往往不比全表扫描的高,ORACLE理所当然对索引“视而不见”,认为该索引的选择性不高。
  但我们考虑另一种情况,如果一百万数据行实际不是在4种deptno值间平均分配,其中有99万行对应着值10,5000行对应值20,3000行对应值30,2000行对应值40。在这种数据分布图案中对除值为10外的其它deptno值搜索时,毫无疑问,如果索引能被应用,那么效率会高出很多。我们可以采用对该索引列进行单独分析,或用analyze语句对该列建立直方图,对该列搜集足够的统计数据,使ORACLE在搜索选择性较高的值能用上索引。
  第十,索引列值是否可为空(NULL)。如果索引列值可以是空值,在SQL语句中那些需要返回NULL值的操作,将不会用到索引,如COUNT(*),而是用全表扫描。这是因为索引中存储值不能为全空。
  第十一,看是否有用到并行查询(PQO)。并行查询将不会用到索引。
  第十二,看PL/SQL语句中是否有用到bind变量。由于数据库不知道bind变量具体是什么值,在做非相等连接时,如“&”,“&”,“like”等。ORACLE将引用缺省值,在某些情况下会对执行计划造成影响。
  如果从以上几个方面都查不出原因的话,我们只好用采用在语句中加hint的方式强制ORACLE使用最优的“执行计划”。
  hint采用注释的方式,有行注释和段注释两种方式。
  如我们想要用到A表的IND_COL1索引的话,可采用以下方式:
  “SELECT * FROM A WHERE COL1 = XXX;"
  注意,注释符必须跟在SELECT之后,且注释中的“+”要紧跟着注释起始符“/*”或“--”,否则hint就被认为是一般注释,对PL/SQL语句的执行不产生任何影响。
两种有效的跟踪调试方法
  ORACLE提供了两种有效的工具来跟踪调试PL/SQL语句的执行计划。
  一种是EXPLAIN
TABLE方式。用户必须首先在自己的模式(SCHEMA)下,建立PLAN_TABLE表,执行计划的每一步骤都将记录在该表中,建表SQL脚本为在${ORACLE_HOME}/rdbms/admin/下的utlxplan.sql。
  打开SQL*PLUS,输入“SET AUTOTRACE
ON”,然后运行待调试的SQL语句。在给出查询结果后,ORACLE将显示相应的“执行计划”,包括优化器类型、执行代价、连接方式、连接顺序、数据搜索路径以及相应的连续读、物理读等资源代价。
  如果我们不能确定需要跟踪的具体SQL语句,比如某个应用使用一段时间后,响应速度忽然变慢。我们这时可以利用ORACLE提供的另一个有力工具TKPROF,对应用的执行过程全程跟踪。
  我们要先在系统视图V$SESSION中,可根据USERID或MACHINE,查出相应的SID和SERIAL#。
  以SYS或其他有执行DBMS_SYSTEM程序包的用户连接数据库,执行“EXECUTE
DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION(SID,SERIAL#,TRUE);”。
  然后运行应用程序,这时在服务器端,数据库参数“USER_DUMP_DEST”指示的目录下,会生成ora__xxxx.trc文件,其中xxxx为被跟踪应用的操作系统进程号。
  应用程序执行完成后,用命令tkprof对该文件进行分析。命令示例:“tkprof tracefile outputfile
explain=userid/password"。在操作系统ORACLE用户下,键入“tkprof”,会有详细的命令帮助。分析后的输出文件outputfile中,有每一条PL/SQL语句的“执行计划”、CPU占用、物理读次数、逻辑读次数、执行时长等重要信息。根据输出文件的信息,我们可以很快发现应用中哪条PL/SQL语句是问题的症结所在。
结果问题还是未解决
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 oracle 索引初始大小 的文章

 

随机推荐