通过索引访问得到表的ROWID,然后根据这些ROWID再去访问表中数据行,就称为回表。Oracle如果执行计划里出现table access by rowid,mysql5.6及以上出现Using MRR就说明要回表。
减少回表次数将提高SQL查询性能。
1、 定义测试表:
CREATE TABLE test (id BIGINT(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY ,
val INT(10) UNSIGNED NOT NULL DEFAULT 0,
source INT(10) UNSIGNED NOT NULL DEFAULT 0
);
CREATE INDEX test_val_index ON test(val ASC);
2、 注入500百万条随机测试数据:
DROP PROCEDURE IF EXISTS twhile;
DROP PROCEDURE IF EXISTS tcountinsert;
DELIMITER //
CREATE PROCEDURE twhile(IN total INT)
BEGIN
DECLARE i INT;
SET i = 0;
WHILE i
SET i = i+1;
END WHILE;
COMMIT;
END
//
DELIMITER ;
DELIMITER //
CREATE PROCEDURE tcountinsert(IN pageCount INT,IN allCount INT)
BEGIN
DECLARE i INT;
SET i = 0;
WHILE i
SET i = i+1;
END WHILE;
END
//
DELIMITER ;
CALL tcountinsert(10000,500);
1、 查询val>500,从20万开始的5条数据,sql如下:
SELECT * FROM test WHERE val>500 LIMIT 200000,5;
执行时间:4.39秒
使用了val上的范围索引,并使用了MRR策略的回表查询。
2、 回表优化后sql如下:
SELECT * FROM test a INNER JOIN (SELECT id FROM test WHERE val>500 LIMIT 200000,5) b ON a.id=b.id;
执行时间:0.17秒
Sql解析:
使用了val上的范围索引,并使用了Using where策略,避免了回表查询。
3、 优化后查询时间提升26倍。
由于达梦dm7在字段较少时,减少回表的优化体现不明显,因此多加入10个字段(t1~t7)
create tablespace test5 datafile ‘/dm7/data/DAMENG/test5_01.dbf’ size 1024;
create user test5 identified by dameng123 default tablespace test5;
CREATE TABLE test5.test (id int PRIMARY KEY identity(1,1),
val int NOT NULL DEFAULT 0,
source int NOT NULL DEFAULT 0,
t1 int NOT NULL DEFAULT 0,
t2 int NOT NULL DEFAULT 0,
t3 int NOT NULL DEFAULT 0,
t4 int NOT NULL DEFAULT 0,
t5 int NOT NULL DEFAULT 0,
t6 int NOT NULL DEFAULT 0,
t7 int NOT NULL DEFAULT 0,
t8 int NOT NULL DEFAULT 0,
t9 int NOT NULL DEFAULT 0,
t10 int NOT NULL DEFAULT 0
);
CREATE INDEX test5.test_val_index ON test5.test(val ASC);
– 创建存储过程twhile,针对单次插入
CREATE PROCEDURE TEST5.TWHILE(TOTAL IN INT) as
BEGIN
declare
I INT;
begin
for I in 1…TOTAL loop
INSERT INTO test5.test (val,source,t1,t2,t3,t4,t5,t6,t7,t8,t9,t10) VALUES (FLOOR(RAND() * 1000),FLOOR(RAND() * 10000),
FLOOR(RAND() * 100),FLOOR(RAND() * 100),FLOOR(RAND() * 100),FLOOR(RAND() * 100),FLOOR(RAND() * 100),FLOOR(RAND() * 100),FLOOR(RAND() * 100),FLOOR(RAND() * 100)
,FLOOR(RAND() * 100),FLOOR(RAND() * 100));
end loop;
COMMIT;
end;
END;
– 创建存储过程tCountInsert,针对单次插入,pageInsert每次事务插入量,allIndex插入总次数
CREATE or replace PROCEDURE TEST5.TCOUNTINSERT(PAGEINSERT IN INT,ALLINDEX IN INT) as
BEGIN
declare
I INT;
SQLTEXT varchar2(100);
begin
for I in 1…ALLINDEX loop
SQLTEXT := ‘call TEST5.twhile(’||PAGEINSERT||’)’;
EXECUTE IMMEDIATE SQLTEXT;
end loop;
COMMIT;
dbms_stats.gather_table_stats(‘TEST5’,‘TEST’);–更新统计信息
end;
END;
call TEST5.TCOUNTINSERT(10000,500);
从20万行开始搜索
执行时间:30.335毫秒
Sql解析:
执行时间:8.813毫秒
3、优化后执行时间提升3.4倍左右。
回表查询对mysql性能影响较大,dm7在插入速度,查询速度方面比mysql好太多。Mysql初始化500万条数据要20-30分钟,dm7在1-2分钟左右即可初始化完成。
Mysql优化前执行时间长大4s,优化后也接近200ms,dm7优化前30ms,优化后8ms,差距几十倍。
Dm7在数据字段很少的时候,回表查询对整体查询影响不大,有回表对查询的影响也较低。在数据字段较多时,减少回表查询执行时间也有几倍的提升。
Dm7整体性能比mysql好很多,国产数据库目前dm7是最接近oracle语法的。在其他查询测试结论方面也跟oracle很相近(相关综合性测试也有报告,待有空上传),有些甚至更好一些。目前我司因国产化的要求,也在逐渐开始替换。