1. 程式人生 > >記一次解決oracle sql效能瓶頸的問題

記一次解決oracle sql效能瓶頸的問題

先上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>

極大提升了效率:
這裡寫圖片描述