Best Practices: Informix Query Performance Tuning Basics

Transcription

Best Practices:Informix Query PerformanceTuning BasicsMike WalkerAdvanced DataToolsmike@advancedatatools.com

Mike WalkerMike Walker has been using Informix databasesfor over 20 years, as a developer and as adatabase administrator.Mike heads up the Remote DBA Support forAdvanced DataTools Corporation.Contact .comOffice: 703-256-0267Cell: 303-909-42652

Webcast Guidelines The Webcast is being recorded. TheWebcast replay and slides may beavailable in a few days. Please Mute your Line. Backgroundsounds will distract everyone. Use the Chat Button in the upper rightto ask questions.3

Performance Tuning Basics Identifying long running queriesExplain plans – Query TuningOptimizer directivesMonitoring the buffer pool usageFinding busy tablesChecking statistics4

Long Running Queries –What’s Running? How to tell if a session is doing anything Start with “onstat -u” First position in the Flags column indicateswhat’s going onB - Waiting for a bufferC - Waiting for a checkpointG - Waiting for a write of the logical-log bufferL - Waiting for a lockS - Waiting for mutexT - Waiting for a transactionY - Waiting for conditionX - Waiting for a transaction cleanup (rollback)Interested in anything that is NOT a “Y” – and last position is a “-”5

Long Running Queries –What’s Running?onstat 381333201118638839872051200128192083406

Long Running Queries –How Long? Use “onstat -g ntt” to find out when theconnection was established and when the lastSQL was 0702ec34587000007030e7cd070000070284e600thread 1553951546951521951510Session :52:05Time of lastSQL7

Long Running Queries Use onstat -u to tell you what is running Use onstat -g ntt to tell you the last timeSQL was submitted Use the results of both to see what’srunning and for how long– How long difference between last SQL timeand current time8

Long Running QueriesCombine the info from the onstats together, repeating at [14:19:24] 3 1422169773 299004393 5[14:19:25][14:19:25][14:19:25][14:19:25] 8129912222368425412808125211:24:30 14:19:21 14:19:21 [14:19:27] 04:49:23 14:19:22 14:19:22 [14:19:27] 3 1423877293 36928045423644 64 ----PR----PR--11:24:30 14:19:21 14:19:21 [14:19:28] 04:49:23 14:19:22 14:19:22 [14:19:28] 21:03:13 14:19:26 14:19:26 [14:19:28] 3 1424729773 3701354932180423644 64 16192 ----PR----PR----P---9

Long Running QueriesFor OLTP, would like to see the SQL time change every second or soSQL time is changing for most sessions approximately every [16:57:33][16:57:33][16:57:33][16:57:33] 1 10937562 504012174 58012104 639460627982342613 :34] 1 10940172 50425264313384 58018924 57:36][16:57:36][16:57:36] 1 10942462 5044795231338455484 58023804 -P-----P-----PR--Sessions 59022843 and 59024816 have been running for 20 minutes and 10 minutes respectively10

Long Running Queries For a session where SQL is being submittedregularly, view the SQL at regular intervals:onstat -g sql SID -r 1Repeat every 1 second If the SQL is changing, then will soon get agood idea of what is going on:– Lots of different statements?– Repeated statements? Maybe with different literalvalues? If different statements are executed, but seeone SQL repeated frequently, then this maybe the first statement to begin investigating11

Long Running Queries Use the same approach with a backgroundprocess that periodically checks how long allSQLs have been running and dump sessioninformation to a file when exceeds athreshold Also use Informix SQL Trace to recordqueries and then retrieve those that ran thelongest SQL Trace is covered extensively elsewhere12

Reviewing Query Plans Now we have found some slow SQL, find outwhat it’s actually doing by obtaining a QueryPlan Turn on Dynamic Explain to get plan for asession:onmode -Y sid 0 1 2 [filename]0 off1 plan statistics on2 only plan on13

Dynamic Query PlansSet Dynamic Explain for Session 10563onmode -Y 10563 1onstat -g sesIBM Informix Dynamic Server Version 12.10.FC5AEE -- On-Line -- Up 1 days 12:01:36 -2947104 ostname 086784dynamicexplainoffoffonoffoffoffoffoffoff14

Dynamic Query PlansExplain plan written to a file in the user’s homedirectory with the SID in the name:-rw-rw-rw- 1 informix informix573 Apr7 11:17 sqexplain.out.10563cat sqexplain.out.10563QUERY: (OPTIMIZATION TIMESTAMP: 04-07-2017 11:17:33)-----select * from snapshotEstimated Cost: 79971Estimated # of Rows Returned: 1199409Query &Query Plan1) informix.snapshot: SEQUENTIAL SCANQuery statistics:-----------------Query Statistics shown because used:onmode –Y sid 1Table map :---------------------------Internal nameTable isticstypetable rows prod est rows rows scan timeest 00.007997115

Dynamic Query Plans Using “onmode -Y” will not produceanything until the next statement runs – sono good for getting the explain plan for asingle, long running statement Limited value if prepared SQL is beingexecuted For a closer look and to start tuning,capture the SQL to a file, and get theexplain plan for that 16

SET EXPLAIN SET EXPLAIN ON / SET EXPLAIN OFF:SET EXPLAIN ON;SELECT * FROM x WHERE y 10;SET EXPLAIN OFF; By default, the query plan is written to the file:sqexplain.out File is created in the current directory (UNIX) If use client app, the file will be in home directoryof the user that SQL was executed as File will be appended to each time more SQL isexecuted17

SET EXPLAINslow1.sql:set explain file to "slow1.exp";set explain on;output to /dev/nullselect c.customer num, o.order numfrom customer c, orders owhere c.customer num o.customer numand c.company "Play Ball!"order by 2;timex dbaccess –e stores demo slow1.sql slow1.out 2 &1 &-rw-rw-rw- 1 informix informix 2167 Apr9 07:50 slow1.exp18

SET EXPLAINQUERY: (OPTIMIZATION TIMESTAMP: 04-09-2017 07:50:47)-----select c.customer num, o.order numfrom customer c, orders owhere c.customer num o.customer numand c.company "Play Ball!"order by 2slow1.expEstimated Cost: 6Estimated # of Rows Returned: 2Temporary Files Required For: Order By1) informix.c: SEQUENTIAL SCANFilters: informix.c.company 'Play Ball!'2) informix.o: INDEX PATH(1) Index Name: informix. 102 4Index Keys: customer num(Serial, fragments: ALL)Lower Index Filter: informix.c.customer num informix.o.customer numNESTED LOOP JOIN19

SET EXPLAINQuery statistics:----------------Table map :---------------------------Internal nameTable name---------------------------t1ct2oAs long as query is allowed tocomplete, Query Statistics will beshown at the end of the plan[ EXPLAIN STAT 1 in ONCONFIG ]typetable rows prod est rows rows scan timeest --------------------scant1132800:00.004typetable rows prod est rows rows scan timeest --------------------scant2423400:00.000typerows prod est rows timeest --nljoin4300:00.006typerows sort est rows rows cons timeest -------------sort43400:00.00020

SET EXPLAINFor long running SQL or for Insert, Updateor Delete operations, use“AVOID EXECUTE” to get the explain planwithout running the SQL:slow2.sql:set explain file to "slow2.exp";set explain on avoid execute;update ordersset ship instruct nullwhere customer num 104;21

SET EXPLAINdbaccess -e stores demo slow2.sqlDatabase selected.set explain file to "slow2.exp";Explain set.set explain on avoid execute;Explain set.update ordersset ship instruct nullwhere customer num 104;0 row(s) updated.If use AVOID EXECUTE willNOT see the Query Statisticsin the Explain PlanWarning! avoid execute has been setDatabase closed.22

Anatomy of a Query PlanQuery SQLCost/Rows Returned/Temp Files/DirectivesTable 1 : Name & Access MethodTable 1 : FiltersTable 1 : Index InfoTable 2 : Name & Access MethodRepeatedfor othertablesTable 2 : FiltersTable 2 : Index InfoTable 1 & 2 : Join MethodSubqueriesQuery Statistics (if enabled)23

Query PlansQUERY: (OPTIMIZATION TIMESTAMP: 04-09-2017 07:50:47)-----select c.customer num, o.order numfrom customer c, orders oQuery SQLwhere c.customer num o.customer numand c.company "Play Ball!"order by 2Estimated Cost: 6Estimated # of Rows Returned: 2Temporary Files Required For: Order By1) informix.c: SEQUENTIAL SCANCost/Rows Returned/TempFiles/DirectivesTable 1 : Name & Access MethodFilters: informix.c.company 'Play Ball!'2) informix.o: INDEX PATHTable 1 : FiltersTable 2 : Name & Access Method(1) Index Name: informix. 102 4Table 2 : IndexIndex Keys: customer num(Serial, fragments: ALL)InfoLower Index Filter: informix.c.customer num informix.o.customer numTable 1 & 2 : Join MethodNESTED LOOP JOIN24

Query Plansselect c.cust id, c.cust name, o.order idfrom customer c, order owhere c.cust id o.cust idand c.cust type 'PREF'and o.pay type ! 'CREDCARD'and o.ship method 'FEDEX'Estimated Cost: 51207Estimated # of Rows Returned: 9000Estimate – if very wrong, thenstats may be out-of-date1) informix.c: SEQUENTIAL SCANFilters: informix.c.cust type 'PREF'2) informix.o: INDEX PATHFilters: (informix.o.ship method 'FEDEX' ANDinformix.o.pay type ! 'CREDCARD' )(1) Index Name: informix.order ix2Index Keys: cust id(Serial, fragments: ALL)Lower Index Filter: informix.c.cust id informix.o.cust idNESTED LOOP JOIN25

Query Plans – Breaking it Down1) informix.c: SEQUENTIAL SCANFilters: informix.c.cust type 'PREF'2) informix.o: INDEX PATHFilters: (informix.o.ship method 'FEDEX' ANDinformix.o.pay type ! 'CREDCARD' )(1) Index Name: informix.order ix2Index Keys: cust id(Serial, fragments: ALL)Lower Index Filter: informix.c.cust id informix.o.cust idNESTED LOOP JOINordercustomerRead ALL RowsRead rows for cust idcust type ‘PREF’Reject those that don’t matchfilters26

Query Plans – Breaking it DownordercustomerRead ALL Rowscust type ‘PREF’Read rows for cust idReject those that don’t match filtersselect count(*)from customer;(count(*))select count(*)from customerwhere cust type 'PREF';(count(*))select count(*)from customer c, order owhere c.cust id o.cust idand c.cust type 'PREF';Results of query 10000025000(count(*))2500006040 row(s) retrieved.27

Query Planscustomer (all rows)customer.cust type ‘PREF’Joins to order tableRows returned from query: 100000 rows: 25000 rows: 250000 rows: 6040 rowsNumber of Rows ReadvsNumber of Rows ReturnedLots of rows read and then discarded!Try and make the number of rows read as close as possibleto those that are needed28

Query StatisticsQuery statistics:-----------------Review the “Filters”Including the filter columns in the index willreduce the rows scanned and the rows discardedTable map :---------------------------Internal (after filtering)t1ct2oRows ReadTable Scan,but fast!typetable rows prod est rows rows scan timeest 15501typetable rows prod est rows rows scan timeest typerows prod est rows timeest --nljoin6040900000:15.2451207This is where thetime was spent29

Query StatisticsQuery statistics:-----------------New index includes ship methodcreate index order ix3 on order(cust id, ship method)Table map :---------------------------Internal nameTable name---------------------------t1ct2oRows Read is much closer to theRows Needed – fewer rowsdiscardedtypetable rows prod est rows rows scan timeest 15501typetable rows prod est rows rows scan timeest yperows prod est rows timeest --nljoin60401285800:01.6125312Faster!30

Sequential Scans If a Query Plan contains a SequentialScan, all rows of the table are read(before any filter is applied) Don’t freak out!– If most of the rows read from the table areneeded, then it may be okay– Consider that many indexed reads of datacan be costly because of the read of theindex, plus the read of the data page31

Sequential ScansA Scan of all Data Pages may be faster than lots ofIndexed ReadsSequential geDataPagePagePageIndexed agePageBut it depends on how many rows are actuallyneededA scan of a large table can trash the cache32

Sequential Scans1) informix.order: SEQUENTIAL SCANFilters: (informix.order.ship method 'FEDEX' ANDinformix.order.pay type 'CREDCARD' )typetable rows prod est rows rows scan timeest .552800011) informix.order: INDEX PATHRows ReadFilters: informix.order.ship method 'FEDEX'(1) Index Name: informix.order ix4Index Keys: pay type order id(Serial, fragments: ALL)Lower Index Filter: informix.order.pay type 'CREDCARD‘typetable rows prod est rows rows scan timeest 2304336Fewer RowsSlower!33

Query Tuning ExampleSELECT inventory.week nr, snip , inventory.quantityFROM product, inventoryWHERE inventory.prod num product.prod numAND inventory.year num 2016AND inventory.quantity 0AND TRIM(product.department '-' product.prod type) IN ('A-1')AND inventory.store IN (201)Estimated Cost: 6828412Estimated # of Rows Returned: 23493501) informix.product: SEQUENTIAL SCANFilters: TRIM ( BOTH ' ' FROM ((informix.product.department '-' ) informix.product.prod type )) 'A-1'2) informix.inventory: INDEX PATHFilters: informix.inventory.quantity 0(1) Index Name: informix.inventory idx3Index Keys: prod num store week nr year num(Key-First) (Serial,fragments: ALL)Lower Index Filter: (informix.inventory.prod num informix.product.prod num AND informix.inventory.store prod type )Index Key Filters: (informix.inventory.year num 2016 )NESTED LOOP JOIN34

Query Tuning ExampleQuery statistics:-----------------Table map :---------------------------Internal nameTable yDespite the ugly scanof the product table,it doesn’t take longtypetable rows prod est rows rows scan timeest 460typetable rows prod est rows rows scan timeest --------------------scant224232123493496 97756302:26.49101typerows prod est rows timeest --nljoin242321234935002:28.196828412Time is spent readinginventory75% of the rows readare discarded35

Query Tuning Example2) informix.inventory: INDEX PATHFilters: informix.inventory.quantity 0(1) Index Name: informix.inventory idx3Index Keys: prod num store week nr year num(Key-First)(Serial, fragments: ALL)Lower Index Filter: (informix.inventory.prod num informix.product.prod num AND informix.inventory.store 201 )Index Key Filters: (informix.inventory.year num 2016 )NESTED LOOP JOIN prod num is supplied from table 1 (good) store has a literal value (good) year num has a literal value (good), BUT it’s position in the index isafter another column (week nr), so it is used as a filter, but not fordrilling into the index (Key-First). Index pages will be read anddiscarded (bad) quantity is not in the index. A jump to the data page is needed toread the value to apply the filter. Rows will be read and discarded(bad)36

Query Tuning Example New Index:inventory( prod num, store, year num, quantity, week nr) year num can now be used for drilling down inthe index quantity is now in the index. Query uses a “ ”operator, but can be used for scanning theindex leaf nodes, PLUS there is no need tocheck the data page week nr is not needed to filter records, but isused in the select clause. Now no need to go tothe data page at all!37

Query Tuning Example – Key-Only.2) informix.inventory: INDEX PATHNo filter anymore(1) Index Name: informix.inventory idx5Index Keys: prod num store year num quantity week nr(Key-Only)(Serial, fragments: ALL)Lower Index Filter: (((informix.inventory.prod num informix.product.prod num AND informix.inventory.store 201 ) ANDinformix.inventory.year num 2016 ) AND informix.inventory.quantity 0 ).Key-OnlyWith a Key-only read, all the columns needed to satisfythe query are in the index. There is no need to read thedata pageIndex must also include columns used by the selectclause and order by to get a key-onlyKey-only reads are very fast!38

Query Tuning Example – Key-OnlyQuery statistics:-----------------Table map :---------------------------Internal nameTable yWith the new index, the queryexecution dropped from 2.5minutes to 2.5 secondstypetable rows prod est rows rows scan timeest 460typetable rows prod est rows rows scan timeest --------------------scant224232123496424 24232100:00.822typerows prod est rows timeest --nljoin242321234964300:02.54199938Previously 2m 26sAll rows read arerows that are needed39

Correlated Sub-QueriesCorrelatedselect c.*from customer cwhere exists (select “X”from order owhere o.custid c.custidand o.stat “OPEN” )Non-Correlatedselect unique c.*from customer c,order owhere c.custid o.custidand o.stat “OPEN”select c.*from customer cwhere custid in (select custidOuter query referenced in Innerfrom order oquery Inner query must be repeated for eachwhere o.stat “OPEN” )row returned by the outer query

Correlated Sub-Queries. AND NOT EXISTS(SELECT C.cust key FROM customer CWHERE C.flag 1 0 AND C.flag 2 0AND C.cust key ST.cust key)Join between C and ST table makesthis a Correlated Subquery1) informix.st: INDEX PATHFilters: (informix.st.cust status IN ('F' , 'Q' , 'H')AND NOT EXISTS subquery )Subquery executed for every row meeting criteria(1) IndexIndexLowerIndexName: informix.site x02Keys: ssn site(Key-First) (Serial, fragments: ALL)Index Filter: informix.st.ssn 'A'Key Filters: (informix.st.site 210 ) snip Subquery:--------Estimated Cost: 9236Estimated # of Rows Returned: 33Scan of tableexecuted repeatedly1) informix.sm: SEQUENTIAL SCANFilters: ((informix.c.cust key informix.st.cust key ANDinformix.c.flag 2 0 ) AND informix.c.flag 1 0 )41

Correlated Sub-Queriestypetable rows prod est rows rows scan timeest .Subquery statistics:-------------------Table map :---------------------------Internal nameTable typetable rows prod est rows rows scan timeest --------------------scant1818633270015447 04:04.08923642

Correlated Sub-Queries. AND NOT EXISTS(SELECT C.cust key FROM customer CWHERE C.flag 1 0 AND C.flag 2 0AND C.cust key ST.cust key)Change EXISTS to a NOT IN andremove the joinAND ST.cust key NOT IN(SELECT C.cust key FROM customer CWHERE C.flag 1 0 AND C.flag 2 0)No longer a Correlated SubquerySubquery will execute one time only43

Correlated Sub-Queriestypetable rows prod est rows rows scan timeest .Subquery statistics:-------------------Table map :---------------------------Internal nameTable name---------------------------t1cFraction of recordsread & much faster!typetable rows prod est rows rows scan timeest With the change, the queryexecution dropped from 4m 5s toless than 2 seconds44

Correlated Sub-Queries Sometimes a CSQ can be a good thing Adding a join to a subquery can reducethe data set returned Efficiencies made to a subquery will becompounded when executed repeatedly45

Optimizer Directives Change the generated query plan byremoving paths from consideration– Will not be ignored (as long as they are valid)– Negative directives (Don’t do something) Great tool for tuning queries46

Optimizer Directives: SyntaxInclude the directive as a comment in theSQL, followed by a “ ”:SELECT -- directive textSELECT { directive text }SELECT /* directive text*/47

Optimizer Directives – 4GLCan be used in 4GL, but must PREPARE theSQL with the Directives so that it is submitted tothe databaselet sql string 'select { USE HASH(o) } c.state, max(order date) ','from order o, cust c ','where o.cust id c.cust id ','group by 1 ','order by 1'prepare sql do unl from sql stringdeclare curs do unl cursor for sql do unl48

Types of Directives Access Methods Join Order Join Methods Star Join Optimization GoalNot all directives areavailable in all engineversionsThe following are for 12.10 Explain Plan Statement Cache49

Types of Directives: Access MethodsFULLPerforms a full-table scanINDEXUses the index specified to access the tableINDEX ALL orMULTI INDEXAccess the table using the specified indexes(Multi-index scan)INDEX SJUse the specified index to scan the table in anindex self-join path.AVOID FULLNo full-table scan on the listed tableAVOID INDEXDoes not use any of the specified indexesAVOID INDEX SJDoes not use an index self-join path for thespecified indexesAVOID MULTI INDEXDoes not use a multi-index scan path for thespecified table50

Types of Directives: Join OrderORDEREDJoin tables or views in the order inwhich they are referenced in the FROMclause of the query51

Types of Directives: Join MethodsUSE NLForces nested loop join on specifiedtablesUSE HASHForces hash join on specified tablesAVOID NLAvoids nested loop join on specifiedtablesAVOID HASHAvoids hash join on specified tables52

Types of Directives: Star JoinAVOID FACTAVOID STAR JOINFACTSTAR JOINAt least one table must be specified. Donot use the table (or any table in the list oftables) as a fact table in star-joinoptimization.The optimizer does not consider a star-joinexecution plan.Exactly one table must be specified. Onlyconsider the specified table as a fact tablein the star-join execution plan.Favor a star-join plan, if one is possible.53

Types of Directives: Optimization GoalFIRST ROWS (N) Tells the optimizer to choose aplan optimized to return the firstN rows of the result setALL ROWSTells the optimizer to choose aplan optimized to return all of theresults“Query level” equivalent of: OPT GOAL configuration parameter (instance level) 0 First Rows, -1 All Rows (default) OPT GOAL environment variable (environment level) SET OPTIMIZATION statement (session level) FIRST ROWS, ALL ROWS54

Types of Directives: Explain PlanEXPLAINTurns SET EXPLAIN ON for thespecified queryEXPLAIN AVOID EXECUTEPrevents the data manipulationstatement from executing; instead,the query plan is printed to theexplain output file55

Types of Directives: Statement CacheAVOID STMT CACHEPrevent the statement from being storedin the statement cache. Forces theoptimizer to reoptimize the statementevery time that the statement is run.56

Directives Examples: ORDEREDselect /* ORDERED */customer.lname, orders.order num, items.total pricefrom customer, orders, itemswhere customer.customer num orders.customer numand orders.order num items.order numand items.stock num 6 and items.manu code "SMT"DIRECTIVES FOLLOWED:ORDEREDDIRECTIVES NOT FOLLOWED:Estimated Cost: 15Estimated # of Rows Returned: 11) informix.customer: SEQUENTIAL SCANTables are accessed in thesame order they are listedin the FROM clause2) informix.orders: INDEX PATH(1) Index Name: informix. 102 4Index Keys: customer num(Serial, fragments: ALL)Lower Index Filter: informix.customer.customer num informix.orders.customer numNESTED LOOP JOIN3) informix.items: INDEX PATH(1) Index Name: informix. 105 12Index Keys: stock num manu code(Serial, fragments: ALL)Lower Index Filter: (informix.items.manu code 'SMT' AND informix.items.stock num 6 )DYNAMIC HASH JOINDynamic Hash Filters: informix.orders.order num informix.items.order num57

Directives Examples : CombineDirectivesselect /* ordered index(customer, zip ix)avoid index(orders," 102 4") */c.lname, o.order num, i.total pricefrom customer c, orders o, items iwhere c.customer num o.customer numand o.order num i.order numand stock num 6and manu code "SMT"58

Directives Examples : ErrorsCheck the Explain Plan to make sure that thedirectives were followed as expected:.DIRECTIVES FOLLOWED:ORDEREDINDEX ( customer zip ix )DIRECTIVES NOT FOLLOWED:AVOID INDEX ( orders 101 4 ) Invalid Index Name Specified.The query will still be executed even with invalid directives59

Optimizer Directives: Pros & ConsPros: Forces the engine to execute the SQL the way thatwe want Sometimes we know better!! Great for testing different plans. What if.?Cons: Forces the engine to execute the SQL the way thatwe want Sometimes the engine knows better!! If new indexes are added, number of rows changessignificantly, or data distributions change then abetter execution plan may be available60

Bufferpool Usage Obvious performance benefit whenqueries are satisfied from the cacheinstead of disk Monitoring the bufferpool can give insightinto proper sizing and direct you toproblem tables, problem queries andmissing indexes61

Bufferpool Turnover Measure the turnover of pages in thebufferpool– Art Kagel’s calculation of Buffer TurnoverBuffer Turnover Ratio ((bufwrits pagreads) /number of buffers ) / time since profile reset– Aim for below 10 - Lower is better– See ratios script on IIUG site for this and otherperformance ratios62

Bufferpool TurnoverBTR Calculation:selectbufsize,nbuffs,round(((( pagreads bufwrites )/nbuffs ) / (select (ROUND (((sh curtime - sh pfclrtime)/60)/60) )from sysshmvals ) ),1) BTRfrom sysbufpool;63

Bufferpool 0004.9820.60.9Way toohigh!64

Bufferpool TurnoverUseful to measure BTR over time to identifypeak periods or look for changes65

Bufferpool TurnoverMeasure the turnover hourly using the delta of values tosee when periods of higher turnover happenThe above showed that the bufferpool turnover spikes inthe early morning hours during report generation66

Bufferpool Use Find out what objects are using thebufferpool Look for tables/indexes that dominate thebufferpool Watch over time to see what swaps in/out Identify the troublemakersDon’t assume that increasing the sizeof the bufferpool is the answer67

o

Informix Query Performance Tuning Basics Mike Walker Advanced DataTools mike@advancedatatools.com . . IBM Informix Dynamic Server Version 12.10.FC5AEE -- On-Line -- Up 1 days 12:01:36 -- . For a closer look and to start tuning, capture the SQL to a file, and get the .