共有17篇文章被收藏推荐
收录于2008-01-01
认领
报错
推荐
mysqlslap是一个mysql官方提供的压力测试工具。以下是比较重要的参数:
–defaults-file,配置文件存放位置
–concurrency,并发数
–engines,引擎
–iterations,迭代的实验次数
–socket,socket文件位置
自动测试:
–auto-generate-sql,自动产生测试SQL
–auto-generate-sql-load-type,测试SQL的类型。类型有mixed,update,write,key,read。
–number-of-queries,执行的SQL总数量
–number-int-cols,表内int列的数量
–number-char-cols,表内char列的数量
例如:
shell>mysqlslap –defaults-file=/u01/mysql1/mysql/my.cnf –concurrency=50,100 –iterations=1 –number-int-cols=4 –auto-generate-sql –auto-generate-sql-load-type=write –engine=myisam –number-of-queries=200 -S/tmp/mysql1.sock
Benchmark
Running for engine myisam
Average number of seconds to run all queries: 0.016 seconds
Minimum number of seconds to run all queries: 0.016 seconds
Maximum number of seconds to run all queries: 0.016 seconds
Number of clients running queries: 50
Average number of queries per client: 4
Benchmark
Running for engine myisam
Average number of seconds to run all queries: 0.265 seconds
Minimum number of seconds to run all queries: 0.265 seconds
Maximum number of seconds to run all queries: 0.265 seconds
Number of clients running queries: 100
Average number of queries per client: 2
指定数据库的测试:
–create-schema,指定数据库名称
–query,指定SQL语句,可以定位到某个包含SQL的文件
例如:
shell>mysqlslap –defaults-file=/u01/mysql1/mysql/my.cnf –concurrency=25,50 –iterations=1 –create-schema=test –query=/u01/test.sql -S/tmp/mysql1.sock
Benchmark
Average number of seconds to run all queries: 0.018 seconds
Minimum number of seconds to run all queries: 0.018 seconds
Maximum number of seconds to run all queries: 0.018 seconds
Number of clients running queries: 25
Average number of queries per client: 1
Benchmark
Average number of seconds to run all queries: 0.011 seconds
Minimum number of seconds to run all queries: 0.011 seconds
Maximum number of seconds to run all queries: 0.011 seconds
Number of clients running queries: 50
Average number of queries per client: 1
前天协助SA排错时,通过tbsql sql发现了使用oreder by rowid做排序的sql,我很好奇这种写法,为什么业务逻辑会通过rowid来排序来实现,常常这种疑惑浪费了我很多时间。
先确认两个问题:
1.为什么会使用rowid来排序
2.一个普通的分页sql,物理读排在第一,为什么每次需要消耗356个的物理读
--------------- ------------ -------------- ------ -------- --------- ----
5,043,897 14,149 356.5 7.7 744.89 53095.33 2800676544
SQL> select/*+ordered use_nl(t1 t2)*/ *
9 from (select rid, rownum as linenum
10 from (select rowid as rid
11 from auc_table
12 where username = 'abc123456789'
13 and approve_status in (0, 1, -9)
14 and ends > SYSDATE
15 order by starts asc,rowid )
16 where rownum <= 100) t1,
17 auc_table t2
18 where t1.linenum >= 1
19 and t1.rid = t2.rowid;
引江枫的论断:
oracle9204版本有这个问题:因为不稳定的排序,同样值的记录的位置在排序后不是固定的。假设两条记录,1,a和1,b,按1排序,那么在第一页的时候,可能最后一条是 1 ,a,翻到第二页,本来第一条应该是1,b的但是因为排序不稳定,可能第一条还是1,a,这样1,b就没有显示出来了
通过讨论可以确认,使用rowid是为了保证分页取数据显示正常,以防不稳定的排序导致有些记录漏掉显示,如果我们能保证每次分页都能取到正确的数据,那不就可以去掉order by rowid。
1.统计username所占的索引块数。
from auc_table
where username = 'abc123456789'and approve_status in (0, 1, -9)and ends > SYSDATE;
1 row selected.
Execution Plan
--------------------------------------------------------
SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=45)
0 SORT (AGGREGATE)
1 INDEX (RANGE SCAN) OF 'IDX_auc_USERNAME' (NON-UNIQUE) (Cost=4 Card=5 Bytes=225)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
5055 consistent gets --差不多我们可以推断这个用户的索引占用了5050个左右的块。
0 physical reads
0 redo size
493 bytes sent via SQL*Net to client
656 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
从上面的结果我们可以看出,这个id占用索引块大概在5000个左右,而且走的索引扫描,没有回表。
order by rowid是为了避免不稳定的排序带来分页sql取值丢失的问题, 如果我们只根据索引来取数据的话,索引中的数据相对位置是不变的,这样是不需要排序,也就没有排序稳不稳定的问题,我们要做的就是根据分页在索引中从头到尾一直把数据取出来而已,没必要通过rowid大小来保证取数据的正确性。
去掉order by rowid排序,性能会有多大的提高呢,我们来对比一下:
1.使用order by rowid排序,取第一页
9 from (select rid, rownum as linenum
10 from (select rowid as rid
11 from auc_table
12 where username = 'abc123456789'
13 and approve_status in (0, 1, -9)
14 and ends > SYSDATE
15 order by starts asc,rowid )
16 where rownum <= 100) t1,
17 auc_table t2
18 where t1.linenum >= 1
19 and t1.rid = t2.rowid;
100 rows selected.
Execution Plan
-----------------------------------------------------
SELECT STATEMENT Optimizer=CHOOSE (Cost=23 Card=5 Bytes=1875 )
0 NESTED LOOPS (Cost=23 Card=5 Bytes=1875)
1 VIEW (Cost=18 Card=5 Bytes=100)
2 COUNT (STOPKEY)
3 VIEW (Cost=18 Card=5 Bytes=35)
4 SORT (ORDER BY STOPKEY) (Cost=18 Card=5 Bytes=290)
5 INDEX (RANGE SCAN) OF 'IDX_auc_USERNAME' (NON-UNIQUE) (Cost=4 Card=5 Bytes=290)
1 TABLE ACCESS (BY USER ROWID) OF 'auc_table' (Cost =1 Card=1 Bytes=355)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
5161 consistent gets =5055(索引块)+100(行块), 如果加上rowid排序的话,应该是把这个username全部数据都要扫描一遍,在排序
62 physical reads
0 redo size
14132 bytes sent via SQL*Net to client
722 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
100 rows processed
2.去掉order by rowid排序,也是只取第一页:
9 from (select rid, rownum as linenum
10 from (select rowid as rid
11 from auc_table
12 where username = 'abc123456789'
13 and approve_status in (0, 1, -9)
14 and ends > SYSDATE
15 order by starts asc )
16 where rownum <= 100) t1,
17 auc_table t2
18 where t1.linenum >= 1
19 and t1.rid = t2.rowid;
100 rows selected.
Execution Plan
----------------------------------------------------------
SELECT STATEMENT Optimizer=CHOOSE (Cost=7 Card=5 Bytes=1875)
0 NESTED LOOPS (Cost=7 Card=5 Bytes=1875)
1 VIEW (Cost=2 Card=5 Bytes=100)
2 COUNT (STOPKEY)
3 VIEW (Cost=2 Card=5 Bytes=35)
4 INDEX (RANGE SCAN) OF 'IDX_auc_USERNAME'
(NON-UNIQUE) (Cost=4 Card=5 Bytes=290)
1 TABLE ACCESS (BY USER ROWID) OF 'auc_table' (Cost =1 Card=1 Bytes=355)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
926 consistent gets --应该是只取到前面100条的数据就退出了,实际上这个逻辑还是有点大,我以为只用100多一点就够
44 physical reads
0 redo size
13963 bytes sent via SQL*Net to client
722 bytes received via SQL*Net from client
8 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
100 rows processed
同样的功能,不同的实现方式性能相差还是很大的,对于我们这种业务量及其繁忙的系统,7.7%的物理读,如果能优化下来,也是相当可观的。
使用nid可以修改一个库的db_name和dbid。当然,如果dbid变更,则需要resetlogs才能打开数据库,因为oracle在内部其实是通过dbid来区分一个数据库的,而只修改db_name的话,则可以noresetlogs。
对于Data Guard环境来说,如果变更了主库的db_name,备库怎么处理?因为db_name不但存在于控制文件中,在每个数据文件的头部也有标识,而备库是不允许执行nid来更名的:
$ nid TARGET=/ DBNAME=test SETNAME=Y DBNEWID: Release 10.2.0.4.0 - Production on Mon Aug 18 13:25:50 2008 Copyright (c) 1982, 2007, Oracle. All rights reserved. Connected to database TEST (DBID=47959353) NID-00131: Control file is not current Change of database name failed during validation - database is intact. DBNEWID - Completed with validation errors.
但如果主库只是要变更db_name的话,备库是不必重做的,只要从主库重新生成备库控制文件即可。此时备库可以继续恢复主库传过来的归档,但是数据文件头部的某个位置还是会保留原来的db_name,只有在备库切换成主库的时候,才会根据控制文件去更新数据文件头。
主库从test更名为test2后,即使重建备库控制文件,备库的数据文件头中的db_name还是保持不变:
$ strings system.dbf | head -n 5
}|{z
TEST
SYSTEM
_SYSSMU1$
_SYSSMU2$
备库在切换成主库以后,文件头中的db_name更新成新的test2:
$ strings system.dbf | head -n 5
}|{z
TEST2
SYSTEM
_SYSSMU1$
_SYSSMU2$
这样虽然看起来不会有什么太大的问题,只是一个标识字段不一样,甚至主库的某个datafile损坏,一样可以复制备库的datafile过来替代。但主备库的数据文件的文件头中存在这么一个不一致,总是一个潜在的风险点,谁知道哪天又触发到oracle的什么bug了。
另外,原备库的临时文件需要重建,因为切换新的主库以后,tempfile的文件头不会根据控制文件修改成新的db_name。
最后附上使用nid修改db_name而不修改dbid的操作步骤(摘自Note:224266.1):
1. Backup the database
2. SHUTDOWN IMMEDIATE of the database
3. STARTUP MOUNT
4. Open one session and run NID with sysdba privileges
% nid TARGET=SYS/password@test_db DBNAME=test_db2 SETNAME=Y
- the value of DBNAME is the new dbname of the database
- SETNAME must be set to Y. The default is N and causes the DBID to be changed also.
5. shutdown IMMEDIATE of the database
6. Set the DB_NAME initialization parameter in the initialization parameter
file to the new database name
7. Create a new password file
8. Startup of the database(without resetlogs)
在LINUX下,如果需要将一台主机上的文件系统迁移至另外一台主机上,并且文件系统是基于LVM创建的,那么可以使用VG导入导出功能将VG和LV在不同主机上迁移。
源主机上操作:
首先在源主机上将文件系统umount:
umount /u05
再将LV和VG inactive:
lvchange -an /dev/vg_u05/lv_u05
vgchange -an vg_u05
最后导出VG:
vgexport vg_u05
目标主机上操作:
导入VG:
vgimport vg_u05
激活VG,MOUNT 文件系统:
vgchange -ay vg_u05
mkdir /u05
mount /dev/vg_u05/lv_u05 /u05
在9.2.0.6和10.2.0.4做了个小小的试验,演示9i和10g对于create index和rebuild index时统计信息的区别。这里列出试验的过程,由于结果比较明显,就懒得写太多文字做说明了。其中tbsql是一个常用脚本的集成环境,tbsql tabstat用户输出一个表以及列和索引的信息,其实就是关联dba_tables/dba_indexes/dba_tab_columns的一个查询。
先来看9.2.0.6的情况:
SQL> create table t as select * from all_objects; Table created. SQL> create index t_id on t(object_id); Index created.
$tbsql tabstat t
Table Number Empty Average Chain Average
OWNER Name of Rows Blocks Blocks Space Count Row Len
---------- ------ -------- ------- ------- -------- -------- --------
SYS T
Column Column Distinct
Name Details Values Density
------------------ ------------------------ -------- -------
OWNER VARCHAR2(30) NOT NULL
OBJECT_NAME VARCHAR2(30) NOT NULL
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NUMBER(22) NOT NULL
DATA_OBJECT_ID NUMBER(22)
OBJECT_TYPE VARCHAR2(18)
CREATED DATE NOT NULL
LAST_DDL_TIME DATE NOT NULL
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
13 rows selected.
B Average Average
Index Tree Leaf Distinct Leaf Blocks Data Blocks Cluster
Name Unique Level Blks Keys Per Key Per Key Factor
--------- --------- ----- ----- -------------- ----------- ----------- -------
T_ID NONUNIQUE
Index Column Col Column
Name Name Pos Details
--------- --------------- ---- ------------------------
T_ID OBJECT_ID 1 NUMBER(22) NOT NULL
可以看到到表,列和索引都没有统计信息。
SQL> alter index t_id rebuild online compute statistics; Index altered.
$tbsql tabstat t
Table Number Empty Average Chain Average
OWNER Name of Rows Blocks Blocks Space Count Row Len
------- ------ -------- ------- ------- -------- -------- --------
SYS T 25,420 348 0 0 0 100
Column Column Distinct
Name Details Values Density
----------------- ------------------------ --------- -------
OWNER VARCHAR2(30) NOT NULL
OBJECT_NAME VARCHAR2(30) NOT NULL
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NUMBER(22) NOT NULL 25,420 0
DATA_OBJECT_ID NUMBER(22)
OBJECT_TYPE VARCHAR2(18)
CREATED DATE NOT NULL
LAST_DDL_TIME DATE NOT NULL
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
13 rows selected.
B Average Average
Index Tree Leaf Distinct Leaf Blocks Data Blocks Cluster
Name Unique Level Blks Keys Per Key Per Key Factor
-------- --------- ----- ----- --------- ----------- ----------- -------
T_ID NONUNIQUE 1 56 25,420 1 1 22,731
Index Column Col Column
Name Name Pos Details
------- ---------- ---- ------------------------
T_ID OBJECT_ID 1 NUMBER(22) NOT NULL
注意到表,object_id列和索引都有统计信息了
再来看10.2.0.4的情况
SQL> create table t as select * from all_objects; Table created. SQL> create index t_id on t(object_id); Index created.
$tbsql tabstat t
Table Number Empty Average Chain Average
OWNER Name of Rows Blocks Blocks Space Count Row Len
---------- ------- -------- ------- ------- -------- ------ --------
SYS T
Column Column Distinct
Name Details Values Density
---------------- ----------------------- --------- -------
OWNER VARCHAR2(30) NOT NULL
OBJECT_NAME VARCHAR2(30) NOT NULL
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NUMBER(22) NOT NULL
DATA_OBJECT_ID NUMBER(22)
OBJECT_TYPE VARCHAR2(19)
CREATED DATE NOT NULL
LAST_DDL_TIME DATE NOT NULL
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
13 rows selected.
B Average Average
Index Tree Leaf Distinct Leaf Blocks Data Blocks Cluster
Name Unique Level Blks Keys Per Key Per Key Factor
------- --------- ----- ------ --------- ----------- ----------- --------
T_ID NONUNIQUE 1 21 9,610 1 1 134
Index Column Col Column
Name Name Pos Details
--------- ------------ ---- ------------------------
T_ID OBJECT_ID 1 NUMBER(22) NOT NULL
注意到表和列都没有统计信息,而索引有统计信息
SQL> alter index t_id rebuild online compute statistics; Index altered.
$tbsql tabstat t
Table Number Empty Average Chain Average
OWNER Name of Rows Blocks Blocks Space Count Row Len
------- ------- -------- ------- ------- -------- ------- --------
SYS T
Column Column Distinct
Name Details Values Density
----------------- ------------------------ ------------ -------
OWNER VARCHAR2(30) NOT NULL
OBJECT_NAME VARCHAR2(30) NOT NULL
SUBOBJECT_NAME VARCHAR2(30)
OBJECT_ID NUMBER(22) NOT NULL
DATA_OBJECT_ID NUMBER(22)
OBJECT_TYPE VARCHAR2(19)
CREATED DATE NOT NULL
LAST_DDL_TIME DATE NOT NULL
TIMESTAMP VARCHAR2(19)
STATUS VARCHAR2(7)
TEMPORARY VARCHAR2(1)
GENERATED VARCHAR2(1)
SECONDARY VARCHAR2(1)
13 rows selected.
B Average Average
Index Tree Leaf Distinct Leaf Blocks Data Blocks Cluster
Name Unique Level Blks Keys Per Key Per Key Factor
-------- --------- ----- ------ ---------- ----------- ----------- --------
T_ID NONUNIQUE 1 21 9,610 1 1 134
Index Column Col Column
Name Name Pos Details
---------- ------------- ---- ------------------------
T_ID OBJECT_ID 1 NUMBER(22) NOT NULL
注意到表和列还是没有统计信息,索引有统计信息。
应该说,10g的处理方式要更加合理一些。我只是alert index rebuild online compute statistics,9i却同时收集了表,列和索引的统计信息,这有点属于自做主张,而10g则正确的按照语法,只计算了索引的统计信息。有个时候,收集列的统计信息,可能导致执行计划选择错误,尤其是这个列是递增列的时候,一定要注意到9i和10g的这个差异。
-
搜索不到您的频道?
>立即加入 -
想与您的读者互动?快来认领您的频道
>立即认领 -
想知道您的博客详细订阅数据么?
>到FeedSky查看 -
想体验专业的博客托管服务么?
>注册BlogBus

