Überwachung problematischer Abfragen im Data Warehouse
Transcrição
Überwachung problematischer Abfragen im Data Warehouse
Überwachung problematischer Abfragen im Data Warehouse-Umfeld Überwachung problematischer Abfragen im Data Warehouse-Umfeld Autoren Dr. Alexander Kick, Credit Suisse, [email protected] Daniel Steiger, Trivadis AG, [email protected] Keywords Adhoc-Abfragen, DWH, Überwachung Summary Adhoc-Abfragen im Data Warehouse-Umfeld brauchen häufig unnötig viele Ressourcen. Wir beschreiben in diesem Artikel, wie solche Abfragen gezielt überwacht werden können. Datum Mai 2005 INHALTSVERZEICHNIS 1 EINFÜHRUNG UND PROBLEMATIK 2 ÜBERWACHUNG DURCH INFORMATIONSREICHE ALERTS 3 BEISPIEL-ALERT 4 IMPLEMENTIERUNG 5 ZUSAMMENFASSUNG 6 LITERATUR Dr. Alexander Kick, Credit Suisse/Daniel Steiger, Trivadis AG Seite 1/9 Überwachung problematischer Abfragen im Data Warehouse-Umfeld Überwachung problematischer Abfragen im Data Warehouse-Umfeld 1 Einführung und Problematik Ein Hauptproblem im Data Warehouse- (DWH) bzw. im Data Mart-Umfeld ist, dass Abfragen auftreten können, die unnötigerweise sehr viele Ressourcen verbrauchen. Dies liegt einerseits daran, dass im Gegensatz zu den meisten OLTP-Systemen Abfragen und Reports durch sogenannte Power-User (z.B. über ein reines Query-Tool) selbst zusammengestellt werden können, und sich diese fehlerhaften Abfragen aufgrund der grossen Datenmenge verheerend auswirken können. Diese schlechten Adhoc-Abfragen entstehen oft durch falsche Klammerung, mangelnde Einschränkungen (Join-Bedingungen) oder sie sind einfach umständlich und zu kompliziert formuliert - vom User oder gar einem Code-generierenden Query-Tool. Häufig laufen derartige Statements extrem lange, benötigen zu viel Temp-Space oder liefern gar kein Ergebnis. Obwohl Benutzer stundenlang auf ein Ergebnis warten müssen oder mit Fehlermeldungen konfrontiert werden, melden sich diese nur gelegentlich oder gar nicht beim DBA oder den Entwicklern. Stattdessen werden die gleichen Abfragen mehrmals gestartet. Dadurch werden zusätzlich Ressourcen (CPU, Space) gebunden und stehen den anderen Benutzern nicht mehr zur Verfügung. Die korrekten Abfragen und Batch-Jobs werden dadurch beeinträchtigt. Oft werden darüber hinaus Meldungen, wie z. B. "cannot extend temp segment in temp tablespace", "cannot extend temp segment in normal tablespace" im Alert-Log generiert, mit denen der DBA nicht viel anfangen kann. Dies liegt daran, dass man rückblickend meist nicht mehr feststellen kann, welche Abfrage diese Probleme verursacht hat. Oft tritt die oben beschriebene Situation jedoch auf, ohne dass der Entwickler bzw. der DBA davon etwas merkt. 2 Überwachung durch informationsreiche Alerts Diese Problematik kann durch eine gezielte Überwachung derartiger Abfragen entschärft werden. Dadurch können problematische Statements rechtzeitig gestoppt und das Problem mit den Benutzern/Entwicklern besprochen werden. Da sowohl die in der Folge korrigierten Statements sehr viel schneller Ergebnisse liefern als auch andere Benutzer deutlich weniger beeinträchtigt werden, verbessert sich die Zufriedenheit aller DB-Benutzer. Darüber hinaus können obengenannte Meldungen vermieden oder zumindest besser beurteilt werden. Mittels Resource Manager liesse sich nur der Ressourcenverbrauch bestimmter Benutzergruppen einschränken. Die beschriebene Problematik liesse sich damit im wesentlichen jedoch nicht lösen. Dr. Alexander Kick, Credit Suisse/Daniel Steiger, Trivadis AG Seite 2/9 Überwachung problematischer Abfragen im Data Warehouse-Umfeld Im Data Warehouse sollte also automatisch und regelmässig geprüft werden, ob gerade problematische Statements ausgeführt werden und der DBA sollte durch Alerts (z. B. E-MailVersand) informiert werden. Damit er die Ursache für die schlechte Performance und den hohen Ressourcenbedarf erkennen kann, sollten die Alerts genügend Informationen enthalten. Diese Informationen, wie z.B. welcher User, welches Statement, bisherige Zeitdauer, bisheriger Temp-Space-Verbrauch, benutzter Ausführungsplan, lassen sich aus v$session, v$sqltext und v$sql_plan extrahieren. Statement und Ausführunsplan sind vor allem deswegen von Bedeutung, weil der Benutzer oft gar nicht das entsprechende SQL-Statement zur Verfügung hat (z.B. durch ein Query-Tool erzeugt) und insbesondere wegen der Row-LevelSecurity (Virtual Private Database), wodurch Abfragen durch zusätzliche Where-Clauses angereichert werden. In v$sql_plan sind derartige Anreicherungen dagegen schon berücksichtigt. Darüber hinaus lässt sich aus dem Ausführungsplan recht schnell das Problem erkennen und beheben. 3 Beispiel-Alert Durch die im nächsten Abschnitt beschriebene implementierte Überwachung wurde z.B. folgender Alert verschickt: Long running queries on PDM01 User Sid SERIAL# Program Status Logon Time Duration ----- ------- ------------------------- -------- ---------------- -------------- 644 17350 sas$ ACTIVE 26.04.2005 12:08 0:40:40 [hh:mm:ss] -----------M533659 select distinct TIME.DATE_RANK_NUM as PER, CIF.CIF_BU_ID as BUID, CIF.CIF_NBR as CIF, CIF.CUSTOMER_SEGMENT_DESC as CIFSEG, CIF.CUSTOMER_TYPE_CD as CIFTYPE, DELK.DELC_RESSORT, DELK.DELC_SECTOR, DELK.DELC_DEPARTMENT, DELK.DELC_GROUP, DELK.DELC_OFFICE, KUV.KUV_RESSORT, KUV.KUV_SECTOR, KUV.KUV_DEPARTMENT, KUV.KUV_GROUP, KUV.KUV_OFFICE from CRDM.CRDM_V_EU_DIM_TIME TIME, CRDM.CRDM_V_EU_DIM_CIF_LE_CROSS CIF, CRDM.CRDM_V_EU_FCT_LE_CROSS FCT, CRDM.CRDM_V_EU_DIM_CREDIT_LE_CROSS CRD, CRDM.CRDM_V_EU_DIM_ACCOUNT_LE_CROSS ACT, CRDM.CRDM_V_EU_DIM_OU_DELC DELK, CRDM.CRDM_V_EU_DIM_OU_KUV KUV where TIME.VALID_FROM_DATE in ('31MAR2005','28FEB2005') and CIF.VALID_FROM_DATE in ('31MAR2005','28FEB2005') and CIF.CIF_BU_ID in ('0011','0012') and CIF.IC_BUSINESS_FLAG = 'N' and CIF.CUSTOMER_TYPE_CD not in ('119','219','319','419','439') and DELK.VALID_FROM_DATE in ('31MAR2005','28FEB2005') and DELK.OU_DELC_ID = CIF.OU_DELC_ID and KUV.VALID_FROM_DATE in ('31MAR2005','28FEB2005') and KUV.OU_KUV_ID = CIF.OU_KUV_ID and DELK.DELC_RESSORT in ('CKP') Dr. Alexander Kick, Credit Suisse/Daniel Steiger, Trivadis AG Seite 3/9 Überwachung problematischer Abfragen im Data Warehouse-Umfeld order by CIF.CIF_NBR -----------------------------------------------------------------------------------------------------------------| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Pstart| Pstop | -----------------------------------------------------------------------------------------------------------------| 0 | SELECT STATEMENT | | | 1 | (0)| |* 2 | | SORT UNIQUE | (0)| | | | | | | 9223P| 8191P| 8191P| 9223P | | 9223P| 8191P| | 9223P | | | | | | CRDM_DIM_OU | 45484 | 2442K| | | | 9223P| 8191P| | | | | | | | CRDM_DIM_CIF | 38598 | 2374K| | 7940 | | 9223P| 8191P| | 9223P | | 9223P| 8191P| | 242P | | 724T| 7248T| | 12G | | 32M| 338M| | 3332 | CRDM_DIM_TIME | 1 | 11 | | 2 | | 32M| | | 3330 | | | | | | 32M| | | | | 22M| | | | | | | | | 22M| | | 722 | | 19M| | | 242P | | | | | | HASH JOIN | 3 | | | | PARTITION RANGE INLIST | KEY(I | KEY(I | |* 4 | TABLE ACCESS FULL 71 (20)| KEY(I | KEY(I | |* 5 | (0)| | HASH JOIN | 6 | 9223P | PARTITION RANGE INLIST | KEY(I | KEY(I | |* 7 | TABLE ACCESS FULL (25)| KEY(I | KEY(I | | 8 | (0)| | MERGE JOIN CARTESIAN | 10 | (66)| | | 9 | (66)| | MERGE JOIN CARTESIAN | MERGE JOIN CARTESIAN | 11 | (58)| (50)| MERGE JOIN CARTESIAN | INDEX FAST FULL SCAN| CRDM_FCT_NK1 1 | 16 | BUFFER SORT 17 | 41 | 18 | INDEX FAST FULL SCAN | CRDM_DIM_ACCOUNT_PK 1 | 19 | 41 | BUFFER SORT | 20 | 1 | 12G | PARTITION RANGE ALL 1 | 937 41 | | (66)| | 41 | 15 | (28)| | | PARTITION RANGE ALL 1 | | | BUFFER SORT 14 | (66)| | | | (31)| | TABLE ACCESS FULL 13 | | | | | (58)| | | | |* 12 | | | | PARTITION RANGE ALL 41 | Dr. Alexander Kick, Credit Suisse/Daniel Steiger, Trivadis AG Seite 4/9 Überwachung problematischer Abfragen im Data Warehouse-Umfeld | 21 | (37)| | 22 | (0)| | INDEX FAST FULL SCAN 1 | 23 | | CRDM_DIM_CREDIT_NK2 | 19M| | | 498 | | 38 | 2090 | | 9223P | | | | | | CRDM_DIM_OU | 38 | 2090 | | 41 | BUFFER SORT | | PARTITION RANGE INLIST | KEY(I | KEY(I | |* 24 | TABLE ACCESS FULL 77 (26)| KEY(I | KEY(I | -----------------------------------------------------------------------------------------------------------------Predicate Information (identified by operation id): --------------------------------------------------2 - access("OU_ID"="OU_KUV_ID") 4 - filter("VALID_FROM_DATE"='31MAR2005' OR "VALID_FROM_DATE"='28FEB2005') 5 - access("OU_ID"="OU_DELC_ID") 7 - filter(("CIF_BU_ID"='0011' OR "CIF_BU_ID"='0012') AND "IC_BUSINESS_FLAG"='N' AND ("VALID_FROM_DATE"='31MAR2005' OR "VALID_FROM_DATE"='28FEB2005') AND "CUSTOMER_TYPE_CD"<>'119' AND "CUSTOMER_TYPE_CD"<>'219' AND "CUSTOMER_TYPE_CD"<>'319' AND "CUSTOMER_TYPE_CD"<>'419' AND "CUSTOMER_TYPE_CD"<>'439') 12 - filter("VALID_FROM_DATE"='31MAR2005' OR "VALID_FROM_DATE"='28FEB2005') 24 - filter("RESSORT"='CKP' AND ("VALID_FROM_DATE"='31MAR2005' OR "VALID_FROM_DATE"='28FEB2005')) Aus dem Ausführungsplan ist ersichtlich, dass die Abfrage fehlerhaft ist (mehrere "MERGE JOIN CARTESIAN", 9223P Rows als Ergebnismenge). Man kann daher sehr schnell den unter 'User' ersichtlichen Benutzer kontaktieren und auf das Problem (in diesem Fall keine Join-Einschränkung in der Where-Clause) hinweisen. 4 Implementierung Im folgenden zeigen wir die wichtigsten Ausschnitte der implementierten Monitoring-PL/SQLPackages. Durch Ausführung der entsprechenden Prozeduren werden lang laufende Abfragen und Abfragen mit zu hohem Sortier-Bedarf in regelmässigen Abständen überwacht, z.B. so: exec monitoring.monitor_longruns(7200, 24); exec monitoring.monitor_hightmp(15000, 48); Diese Prozeduren starten einen Job, der die Prozedur longruns oder hightmp aufruft. Dabei wird die Schwelle bei hightmp in MB und bei longruns in Sekunden angegeben. Die beiden Prozeduren werden also jede Stunde/halbe Stunde mit den Schwellwerten 7200 Sekunden/15000 MB aufgerufen. In der folgenden Implementierung dieser beiden Prozeduren werden entsprechende Cursor geöffnet und zusammen mit anderen Parametern an die Dr. Alexander Kick, Credit Suisse/Daniel Steiger, Trivadis AG Seite 5/9 Überwachung problematischer Abfragen im Data Warehouse-Umfeld Prozedur show_problem_stmts weitergereicht. Dabei sorgt program not like '%(P%)' dafür, dass nur die Hauptprozesse (und nicht die parallelen Slave-Prozesse) ausgewählt werden. Die verwendete Hilfsfunktion to_hhmiss(a.last_call_et) formatiert die Zeitdauer in Stunden, Minuten u. Sekunden. procedure hightmp(threshold number, notify boolean) is tc sys_refcursor; blksize sys.v_$parameter.value%type; subject varchar2(50); header varchar2(200); underl varchar2(200); begin select value into blksize from sys.v_$parameter where name='db_block_size'; open tc for select distinct rpad(a.username,10) || rpad(a.sid,7) || rpad(a.serial#,9) || rpad(a.program,27) || rpad(a.status,10) || rpad(to_char(a.logon_time,'dd.mm.yyyy hh24:mi'),18) || rpad(to_hhmiss(a.last_call_et),20) ||rpad(b.mb,14) || rpad(a.audsid,8) who, a.sql_address, a.sql_hash_value from sys.v_$session a, (select audsid, sum(mb) mb from (select sqlhash, sum(blocks)*blksize/1024/1024 mb from sys.v_$sort_usage group by sqlhash) u, (select distinct audsid, sql_hash_value from sys.v_$session) v where u.sqlhash = v.sql_hash_value group by audsid) b where a.audsid = b.audsid and a.program not like '%(P%)' and a.username not in ('SYS','SYSTEM') and b.mb > threshold; subject:= 'Queries with high temp usage on '; header := 'User Sid SERIAL# Duration [hh:mm:ss] TmpSpace [MB] Audsid underl := '-------- ----- ------- Program Status Logon Time -------- ---------------- '; ------------------------- ------------------- ------------- --------'; show_problem_stmts(threshold, notify, tc, subject, header, underl); end; procedure longruns(threshold number, notify boolean) is tc sys_refcursor; subject varchar2(50); header varchar2(200); underl varchar2(200); begin open tc for SELECT rpad(username,10) || rpad(sid,7) || rpad(serial#,9) || rpad(program,27) || rpad(status,10) || rpad(to_char(logon_time,'dd.mm.yyyy hh24:mi'),18) || rpad(to_hhmiss(last_call_et),21) who, sql_address, sql_hash_value Dr. Alexander Kick, Credit Suisse/Daniel Steiger, Trivadis AG Seite 6/9 Überwachung problematischer Abfragen im Data Warehouse-Umfeld FROM sys.v_$session WHERE username IS NOT NULL AND status = 'ACTIVE' AND program NOT LIKE '% (P%)' AND username not like 'SYS%' AND last_call_et > threshold; subject:= 'Long running queries on ' ; header := 'User Sid SERIAL# Program Status Logon Time ----- ------- ------------------------- -------- ---------------- Duration [hh:mm:ss]'; underl := '--------------------------'; show_problem_stmts(threshold, notify, tc, subject, header, underl); end; Im folgenden Ausschnitt sind die wichtigeren Hilfsfunktionen zu sehen. exec_plan retourniert den Ausführungsplan, sql_query liefert den Text der problematischen Abfrage, der mittels fold_str (aus Platzgründen nicht gezeigt) in brauchbare Zeilen umformatiert wird (Zeilenumbruch nach weniger als 100 Zeichen bei einem Leerzeichen). show_problem_stmts sucht die entsprechenden problematischen Statements und fügt die dazugehörigen Informationen (User, Laufzeit, SQL-Text, Ausführungsplan, etc.) in ein StringArray ein, das dann an eine E-Mail-Prozedur (ähnlich wie in [1] dokumentiert) übergeben und so verschickt wird. function exec_plan(p_address in sys.v_$sqltext.address%type, p_hash_value in sys.v_$sqltext.hash_value%type) return plan_line is plan_output plan_line; begin delete from plan_table; insert into plan_table select ADDRESS, sysdate, 'REMARKS', OPERATION, OPTIONS, OBJECT_NODE, OBJECT_OWNER, OBJECT_NAME, 0, 'OBJECT_TYPE', OPTIMIZER, SEARCH_COLUMNS, ID, PARENT_ID, POSITION, COST, CARDINALITY, BYTES, OTHER_TAG, PARTITION_START, PARTITION_STOP, PARTITION_ID, OTHER, DISTRIBUTION, CPU_COST, IO_COST, TEMP_SPACE, ACCESS_PREDICATES, FILTER_PREDICATES from sys.v_$sql_plan where address = p_address and hash_value = p_hash_value; select plan_table_output bulk collect into plan_output from table(dbms_xplan.display('plan_table',null,'serial')); return plan_output; end; function sql_query(p_address in sys.v_$sqltext.address%type, p_hash_value in sys.v_$sqltext.hash_value%type) return varchar2 as l_text varchar2(4000) := ''; begin Dr. Alexander Kick, Credit Suisse/Daniel Steiger, Trivadis AG Seite 7/9 Überwachung problematischer Abfragen im Data Warehouse-Umfeld for x in (select sql_text from sys.v_$sqltext where address = p_address and hash_value = p_hash_value order by piece) loop l_text := l_text || x.sql_text; exit when length(l_text) > 3930; end loop; return l_text; end; procedure show_problem_stmts(threshold number, notify boolean, cur sys_refcursor, subj varchar2, header varchar2, underl varchar2) is type stmt_info is record (who varchar(500), sql_address sys.v_$sqltext.address%type, sql_hash_value sys.v_$sqltext.hash_value%type); c stmt_info; notes notification.msgs; plan_output plan_line; dbname varchar2(10); subject varchar2(50); begin select name into dbname from sys.v_$database; subject:= subj || dbname; loop fetch cur into c; exit when cur%notfound; if notify then notes.delete; notes(1):= chr(10) || subject || chr(10); notes(2):= header; notes(3):= underl; notes(4):= c.who || chr(10); if (c.sql_hash_value != 0) then notes(5) := fold_str(sql_query(c.sql_address, c.sql_hash_value)); plan_output:= exec_plan(c.sql_address, c.sql_hash_value); for i in 1.. plan_output.last loop notes(5 + i):= plan_output(i); end loop; end if; notification.notify(dbname, notes, subject, null, true, false, recipl); else … end if; end loop; end; 5 Zusammenfassung Weil Data Warehouses bzw. Data Marts fast immer auch für Adhoc-Anforderungen benutzt werden, können problematische Abfragen auftreten, die das System unnötigerweise belasten. Durch eine gezielte Überwachung derartiger Abfragen und gleichzeitiger Extraktion wichtiger Dr. Alexander Kick, Credit Suisse/Daniel Steiger, Trivadis AG Seite 8/9 Überwachung problematischer Abfragen im Data Warehouse-Umfeld Informationen (SQL-Text, Ausführungsplan) sind der DBA und der Entwickler in der Lage, effektiv geeignete Massnahmen in die Wege zu leiten. Durch die beschriebene Überwachung konnte im Data Mart der Credit Suisse darüber hinaus auch nachgewiesen werden, dass die sehr hohen Spitzenwerte beim Gesamt-Temp-Space-Verbrauch mit fehlerhaften Abfragen korrespondierten und infolgedessen der Temporary Tablespace von vorher ca. 500 GB auf weniger als 100 GB reduziert werden konnte. 6 Literatur [1] Connor McDonald. Mastering Oracle PL/SQL: Practical Solutions. 2004. ISBN 1-59059217-4. Dr. Alexander Kick, Credit Suisse/Daniel Steiger, Trivadis AG Seite 9/9