記一次解決oracle sql效能瓶頸的問題
阿新 • • 發佈:2018-12-31
先上sql:
SELECT
(SELECT M.ALBUM_ID FROM ALBUM_R_MUSIC AM,ALBUM M WHERE AM.MUSIC_ID = M.MUSIC_ID AND AM.ALBUM_ID = M.ALBUM_ID AND ROWNUM = 1) ALBUM_ID,
(SELECT M.ALBUM_NAME FROM ALBUM_R_MUSIC AM,ALBUM M WHERE AM.MUSIC_ID = M.MUSIC_ID AND AM.ALBUM_ID = M.ALBUM_ID AND ROWNUM = 1) ALBUM_NAME,
(SELECT TO_CHAR(WM_CONCAT(T.ARTIST _ID || ':' ||
T.ARTIST_NAME))
FROM MUSIC_R_ARTIST MR, ARTIST T
WHERE M.MUSIC_ID = MR.MUSIC_ID(+)
AND MR.ARTIST_ID = T.ARTIST_ID
AND MR.ARTIST_TYPE = 1) ARTIST_ID,
M.MUSIC_ID,
M.LENGTH,
M.MUSIC_NAME,
M.SINGER_NAME,
M.RANK _NUM,
M.PUBLISH_YEAR,
M.STATUS
FROM
<if test="tagId != null">
TAG TA,
OBJECT_R_TAG O,
</if>
MUSIC_R_ARTIST T,
ARTIST_R_TYPE Y,
MUSIC M
<where>
T.ARTIST_ID = Y.ARTIST_ID
AND Y.TYPE_ID = '1'
AND T.MUSIC_ID = M.MUSIC_ID
AND M.STATUS = '1'
AND T.ARTIST_TYPE = 1
<if test="tagId != null">
AND M.MUSIC_ID = O.OBJECT_ID(+)
AND TA.TAG_ID = O.TAG_ID
AND TA.TAG_ID = #{tagId}
AND O.OBJECT_TYPE = 1
</if>
</where>
</php>
這個sql有九百多萬條資料,分頁採用的mybatis框架的RowBounds類。會把整個結果集掃描一次,很耗時間,大概分一次頁要5S左右,到後面幾頁可能需要幾分鐘。。。
解決辦法是將要關聯的表寫成儲存過程,將MUSIC_R_ARTIST T,ARTIST_R_TYPE Y,MUSIC M這三張需要關聯的表融合成一張大的表,並且將rownum作為一列,加上索引。儲存過程會提前把需要的資料跑出來,這樣我們在查詢的時候去操作musicianas,如下:
CREATE OR REPLACE
procedure migu_musician_songs
AS
begin
execute immediate 'drop table temp_musicianas';
execute immediate 'create table temp_musicianas As SELECT m.*,rownum rn
from MUSIC M
where exists
(select 1
from (select music_id
from (select artist_id from ARTIST_R_TYPE where type_id = 1) Y,
MUSIC_R_ARTIST T
where y.artist_id = t.artist_id) t
where t.music_id = m.music_id
and m.status = 1)';
execute immediate 'rename musicianas to temp_musicianas1';
execute immediate 'rename temp_musicianas to musicianas';
execute immediate 'create index IND_musicianas_rn on musicianas(rn)';
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
這樣我們可以通過行號,也就是rownum去做分頁,取得從startIndex到endIndex的資料,就是我們需要的這一頁的資料。sql如下:
SELECT
(SELECT M.ALBUM_ID FROM ALBUM_R_MUSIC AM,ALBUM M WHERE AM.MUSIC_ID = M.MUSIC_ID AND AM.ALBUM_ID = M.ALBUM_ID AND ROWNUM = 1) ALBUM_ID,
(SELECT M.ALBUM_NAME FROM ALBUM_R_MUSIC AM,ALBUM M WHERE AM.MUSIC_ID = M.MUSIC_ID AND AM.ALBUM_ID = M.ALBUM_ID AND ROWNUM = 1) ALBUM_NAME,
(SELECT TO_CHAR(WM_CONCAT(T.ARTIST_ID || ':' ||
T.ARTIST_NAME))
FROM MUSIC_R_ARTIST MR, ARTIST T
WHERE M.MUSIC_ID = MR.MUSIC_ID(+)
AND MR.ARTIST_ID = T.ARTIST_ID
AND MR.ARTIST_TYPE = 1) ARTIST_ID,
M.MUSIC_ID,
M.LENGTH,
M.MUSIC_NAME,
M.SINGER_NAME,
M.RANK_NUM,
M.PUBLISH_YEAR,
M.STATUS
FROM
<if test="tagId != null">
OBJECT_R_TAG O,
</if>
musicianas M
<where> 1= 1
<if test="tagId != null">
AND M.MUSIC_ID = O.OBJECT_ID(+)
AND o.TAG_ID = #{tagId}
AND O.OBJECT_TYPE = 1
</if>
and m.rn between ${startIndex} and ${endIndex}
</where>
極大提升了效率: