Download presentation
Presentation is loading. Please wait.
1
Някои смъртни грехове спрямо производителността на вашата база от данни Автор: Владимир Андреев, Semantec GmbH Лектор: Стоян Иванов, Семантек България ООД
2
За автора и лектора Съответно 7 и 11 години опит с Оракъл Голям опит в повишаване на производителността на базата Оценка на производителността на много реално действащи големи бази от данни –Различни индустрии (automotive, pharmaceutical, chip production, public sector, banking, machine building, telecommunications, etc.) –Различна натовареност (OLTP, DW, Web) –Различни размери (100 MB – 500 GB) –Различни архитектури (2-tier, 3-tier) –Различни технологии (PL/SQL, C++, Java, Forms, ABAP, Teamcenter, Vignette, …)
3
Основни проблеми Проблеми в архитектурата: “независимост” от базата чрез isolation layers =Под-оптимална производителност за всяка база =По-висока цена за разработка и поддръжка Проблеми в дизайна: row-by-row processing =Непреодолими лимити по отношение на производителността и възможността за разширяване Проблеми в кода: Un-sharable SQL =Disaster waiting to happen
4
Middle layers Application servers –Много качествени с мощен език за комуникация с базата: SAP, BAAN –Custom – съществува риск да са твърде ограничени в комуникацията си с базата Database isolation layers –Добри: DAO/OLEDB, ODBC, JDBC, … –Подобряващи се: J2EE Persistency Layers (например TopLink) –Custom – обикновено са извор на проблеми
5
Database Isolation Layers API със ограничена или липсваща поддръжка за: –Не-стандартен SQL (with, merge, connect by, analytics, hints, joins, …) –Извикване на съхранени процедури и функции –Не-поддържане на “ref cursors”, обектни типове,... –Неподдържане на bind променливи Поддръжка на модела на данните, включително и индексите Генериране на под-оптимален SQL
6
Примери “Няма възможност за контрол на SQL” “Application server-а не може да работи с CBO” “Налага се да лъжем междинния слой”
7
Обработка на записите ред по ред Изглежда лесно за писане и разбиране Негативни последици: –Излишни round-trip –Превключване на контексти –Увеличена натовареност на сървъра –Увеличена натовареност на мрежата Row-by-row = Slow-by-slow
8
Slow-by-Slow Processing По мрежата –Увеличен трафик –Забавянията по мрежата се мултиплицират На същата машина (използвайки IPC) –Доброволно превключване на контексти Вътре в базата –“Превключване на контексти” между SQL engine и PL/SQL engine
9
Пример FOR EACH SELECT c1 FROM t1 WHERE … LOOP SELECT c2 FROM t2 WHERE c3 = :c1; SELECT * FROM t3 WHERE c4 = :c2; END LOOP; Може да бъде заменено с SELECT * FROM t3 WHERE c4 IN (SELECT c2 FROM t2 WHERE c3 IN (SELECT c1 FROM t1 WHERE …)); SELECT *
10
Пример For r in (select Data1, id1 from table1) loop Select Data2 into d2 from table2 where id=r.id1; /* do something with r.Data1 and Data2 */ End loop; По-добре For r in (select Data1, Data2 from table1, table2 where id=id1) loop /* do something with Data1 and Data2 */ End loop;
11
Пример Create or replace view VM01_WORKFLOW_STEPS_ACT as SELECT T.ID, T.USER_ID, T.WORKFLOW_ID, T.CONTENT_ID FROM TM01_WORKFLOW_STEPS T WHERE NUMMER = FM01_WORKFLOW_STEPS_ACT(T.CONTENT_ID); Create or replace FUNCTION "FM01_WORKFLOW_STEPS_ACT" (vCONTENT_ID IN NUMBER)RETURN NUMBER IS vNr NUMBER; BEGIN SELECT MAX(NUMMER) INTO vNr FROM TM01_WORKFLOW_STEPS WHERE CONTENT_ID=vCONTENT_ID; RETURN vNr; EXCEPTION WHEN OTHERS THEN RETURN NULL; END FM01_WORKFLOW_STEPS_ACT;
12
По-добре Create or replace view VM01_WORKFLOW_STEPS_ACT as SELECT T.ID, T.USER_ID, T.WORKFLOW_ID, T.CONTENT_ID FROM TM01_WORKFLOW_STEPS T WHERE NUMMER = (select max(nummer) from TM01_WORKFLOW_STEPS where CONTENT_ID=T.CONTENT_ID); или Create or replace view VM01_WORKFLOW_STEPS_ACT as select * from ( SELECT T.ID, T.USER_ID, T.WORKFLOW_ID, T.CONTENT_ID, max(nummer) over (partition by CONTENT_ID) mNum FROM TM01_WORKFLOW_STEPS T ) where nummer=mNum;
13
Пример SELECT /*+ FIRST_ROWS */ED.EVENT_DETAIL_ID FROM ASTCAL_EVENT_DETAIL ED, TM01_FOLGE_ASTCAL FA, TA01_CONTENT_CONTENT Y, TM01_SENDUNG S, TM01_PROGRAMM P WHERE ED.EVENT_MASTER_ID = FA.ASTCAL_EVENT_MASTER_ID AND FA.CONTENT_ID = Y.LINK_CONTENT_ID AND Y.CONTENT_ID = S.CONTENT_ID AND S.PROGRAMM_ID = P.ID AND ED.EVENT_DETAIL_ID != :b1 AND :b2 ED.START_DATE AND FM01_PRG_COMPARE_ID(:b4,P.CONTENT_ID) = 1; FUNCTION "FM01_PRG_COMPARE_ID" (vID1 IN NUMBER,vID2 IN NUMBER) RETURN NUMBER IS vArt NUMBER; begin SELECT ART INTO vART FROM TM01_PROGRAMM WHERE CONTENT_ID=vID1; IF vArt=2 THEN -- TV SELECT ART INTO vART FROM TM01_PROGRAMM WHERE CONTENT_ID=vID2; IF vArt=2 THEN -- auch TV,also ok RETURN 1; END IF; ELSE -- Radio => ID's vergleichen IF vID1=vID2 THEN RETURN 1; END IF; RETURN 0; END FM01_PRG_COMPARE_ID;
14
По-добре SELECT /*+ FIRST_ROWS */ED.EVENT_DETAIL_ID FROM ASTCAL_EVENT_DETAIL ED, TM01_FOLGE_ASTCAL FA, TA01_CONTENT_CONTENT Y, TM01_SENDUNG S,TM01_PROGRAMM P2, (select art from TM01_PROGRAMM where CONTENT_ID=:b4) P1 WHERE ED.EVENT_MASTER_ID = FA.ASTCAL_EVENT_MASTER_ID AND FA.CONTENT_ID = Y.LINK_CONTENT_ID AND Y.CONTENT_ID = S.CONTENT_ID AND S.PROGRAMM_ID = P2.ID AND ED.EVENT_DETAIL_ID != :b1 AND :b2 ED.START_DATE and (p1.ART = 2 and p2.ART = 2 or p1.ART!=2 and :b4=p2.CONTENT_ID); Последния предикат може да бъде заменен от еквивалентен, но може би по читаем: and decode(p1.art,2, decode(p2.art,2,1), decode(:b3,p2.CONTENT_ID,1,0))=1
15
Пример cursor c1 is select id from t1 where…; … open c1; loop exit when c1%notfound; select x1 into v1 from … where p1=c1.id; select x2 into v2 from … where p2=c1.id; insert into t2 values (v1, v2, …); end loop; По-добре: insert into t2 select x1, x2, … from t1, (select x1,p1 from …), (select x2,p2 from …), … where … /* conditions for t1 */ and p1=t1.id and p2=t2.id …;
16
Ефект върху 6-процесорна система
17
Un-sharable SQL Най-лошия тип – литерали вместо bind променливи Лош тип – Динамично изграждани in- или or- списъци Почти безреден тип – Малки/големи букви, излишни интервали и табулации, коментари, различни имена на bind променливите Изключение: Хистограми
18
Литерали и bind променливи – PL/SQL Лош вариант: execute immediate ‘delete from T where id=‘||id_to_delete; По-добър вариант: execute immediate ‘delete from T where id=:dellID’ using id_to_delete; Най-добре: delete from T where id=id_to_delete;
19
Литерали и bind променливи - Java Лош вариант: Statement stmt = conn.createStatement(); stmt.executeUpdate(“delete from T where id=“+Integer.toString(id_to_delete); По-добър вариант: PreparedStatement pstmt = conn.prepareStatement(“delete from T where id=?”); pstmt.setInt(1, id_to_delete); pstmt.execute();
20
Пример – динамичен SQL /*Ermittlung g_ausbildung*/ source_cursor := DBMS_SQL.OPEN_CURSOR; statement := 'SELECT t1.faktor FROM loader_faktoren_pr_segment t1, dim_person t2 WHERE t2.kundennummer = '||val_p_kunden.kundennummer_echt||' AND t1.art = ''Ausbildung'' AND t2.ausbildung_s = t1.schluessel'; DBMS_SQL.PARSE(source_cursor, statement, dbms_sql.NATIVE); DBMS_SQL.DEFINE_COLUMN(source_cursor, 1, g_ausbildung_tmp); dummy := DBMS_SQL.EXECUTE(source_cursor); IF DBMS_SQL.FETCH_ROWS(source_cursor) > 0 THEN DBMS_SQL.COLUMN_VALUE(source_cursor, 1, g_ausbildung); ELSE g_ausbildung := 1; END IF; DBMS_SQL.CLOSE_CURSOR(source_cursor);
21
Пример – native dynamic SQL BEGIN EXECUTE IMMEDIATE 'SELECT t1.faktor FROM loader_faktoren_pr_segment t1, dim_person t2 WHERE t2.kundennummer = :kn AND t1.art = ''Ausbildung'' AND t2.ausbildung_s = t1.schluessel AND ROWNUM=1' INTO g_ausbildung USING val_p_kunden.kundennummer_echt; EXCEPTION WHEN no_data_found THEN g_ausbildung := 1; END; Още по-добре – обикновен не-динамичен SQL: BEGIN SELECT t1.faktor INTO g_ausbildung FROM loader_faktoren_pr_segment t1, dim_person t2 WHERE t2.kundennummer = val_p_kunden.kundennummer_echt AND t1.art = 'Ausbildung' AND t2.ausbildung_s = t1.schluessel AND ROWNUM=1; EXCEPTION WHEN no_data_found THEN g_ausbildung := 1; END;
22
Пример UPDATE ABRUFE SET ENDE_ABRUF= TO_DATE('27.01.2004 10:50:00','DD.MM.YYYY HH24:MI:SS') WHERE ABRUF_ID = 242392; begin PM01_EXPORT_PROG_BEITRAG(:result, '1209923'); end; statement := 'SELECT t1.faktor FROM loader_faktoren_pr_segment t1, dim_person t2 WHERE t2.kundennummer = '||val_p_kunden.kundennummer_echt||' AND t1.art = ''Ausbildung'‘ AND t2.ausbildung_s = t1.schluessel'; DBMS_SQL.PARSE(source_cursor, statement, dbms_sql.NATIVE); SELECT * FROM apttab WHERE apttab.finr = 1 AND apttab.artnr = '122-0147-0 ' AND apttab.varnr = 0 AND apttab.appos = 30 Select * from ODIN_STACK where ODS_INDEX ='PODSB_5714733';
23
Пример select A.CONTENT_ID, A.LINK, A.EXTENSION from VA01_CONTENT_AUDIO_L AL, VA01_CONTENT_AUDIO A where AL.AUDIO1_ID=A.CONTENT_ID and AL.ID = 11541; select A.CONTENT_ID, A.LINK, A.EXTENSION from VA01_CONTENT_AUDIO_L AL, VA01_CONTENT_AUDIO A where AL.AUDIO1_ID=A.CONTENT_ID and AL.ID = 46309; SELECT TITEL, AUTOR, '', '', '', TEASER, '' from VA01_CONTENT_BEITRAG_CONT where CONTENT_ID = 1249596; SELECT TITEL, AUTOR, '', '', '', TEASER, '' from VA01_CONTENT_BEITRAG_CONT where CONTENT_ID = 1249924; begin PD01_FRESH_ARTIKEL(:result, 7569, 1, 'and c.id not in (1272117,1270457) '); end; begin PD01_FRESH_ARTIKEL(:result, 7569, 1, 'and c.id not in (1272117,1270457,1268878) '); end; begin PD01_FRESH_ARTIKEL(:result, 7570, 1, 'and c.id not in (1263619) '); end; begin PM01_EXPORT_PROG_BEITRAG(:result, '1209923'); end; begin PM01_EXPORT_PROG_BEITRAG(:result, '1209926'); end; begin PM01_EXPORT_PROG_BEITRAG(:result, '1209930'); end;
24
Как да откриваме un-sharable SQL Accept len prompt "Prefix length to consider:" SELECT * FROM v$sql WHERE UPPER (SUBSTR (sql_text, 1, &len)) IN (SELECT UPPER (SUBSTR (sql_text, 1, &len)) FROM v$sql GROUP BY UPPER (SUBSTR (sql_text, 1, &len)) HAVING COUNT (*) > 1) ORDER BY UPPER (sql_text);
25
Как да откриваме un-sharable SQL equivalent_sql.sh
26
Благодарим ви за вниманието За контакти: Andreev@semantec.de Stoyan.Ivanov@semantec.bg
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.