er

82
ASE 15 Query Tuning MAY 2011 JEFF TALLMAN SENIOR SOFTWARE ENGINEER/ARCHITECT

Transcript of er

Page 1: er

ASE 15 Query Tuning

MAY 2011

JEFF TALLMAN

SENIOR SOFTWARE ENGINEER/ARCHITECT

Page 2: er

The 4 Stages of Query TuningThe 4 Stages of Query Tuning

1. Finding Query with Issues

2. Analyzing QP Optimization

3. Manually Tuning Query

4. Deploying the Fix

2 – © 2011 Sybase, Inc – May 3, 2011

Today’s Session will focus on the primarily on the first two

with a look at how to use a couple of ASE 15’s new features

for the third topic.

Page 3: er

Finding Queries With Issues

3 – Sybase Confidential – May 3, 2011

Page 4: er

Tools For Finding Query IssuesTools For Finding Query Issues

• QP Metrics (aka sysquerymetrics)

� good for adhoc queries

� Basis for QP Tune utility

� Filter to focus in on just slow queries

� Use a login trigger to limit to just a representative number of users

• MDA

� Good for stored procs, statement cache, batch processes

4 – © 2011 Sybase, Inc – May 3, 2011

� Good for stored procs, statement cache, batch processes� monSysStatement for stored procs & batch processes� monCachedStatement for statement cache

• App Tracing

� Good for interactively capturing query syntax and diagnostics

� Due to potential output volume, this should be used only for narrow windows of time

• This part of today’s session will focus on QP Metrics

� With some look at App Tracing as this ties into QP optimization

Page 5: er

QP Metrics aka sysquerymetricsQP Metrics aka sysquerymetrics

• Advantages over MDA

� No “loss” due to over-running the MDA pipe size

� Very easy to implement

� Easy to identify statements across sessions (due to hashkey)

� Ability to limit collection to just one or a few sessions (vs. everyone)

• Comments/Gotcha’s

� Can consume a lot of disk space in system segment

� Can impact query execution speed

5 – © 2011 Sybase, Inc – May 3, 2011

� Can impact query execution speed� There is a buffer of metrics (similar to audit queue)� But if this gets full, each new captured query will need to wait until buffer is destaged

…slows query exec� Enabling statement cache/literal autoparam can help

� Restricted to each database individually � <database>..sysquerymetrics is view on <database>..sysqueryplans

� Best with ad-hoc queries� Not very good with stored procedures or cached statements unless they are compiled

after QP metrics enabled� …and only good at finding queries with issues - not runaway processes in tight loop

� Tip: Use MDA/monSysStatement as a starting point� If it points to a bad ad-hoc query as a likely cause - use QP metrics to find the query

Page 6: er

What Really Is QP Metrics??What Really Is QP Metrics??

• A repository of queries and their execution metrics

� Captures the query executions and metrics based on configurable

thresholds (e.g. only capture queries that run longer than 5 seconds)

� Stores the query text and metrics in system tables

� Exposes the results via a view in each database

• A utility stored procedure

6 – © 2011 Sybase, Inc – May 3, 2011

• A utility stored procedure

� Allows sets of metrics to be backed up for later comparison

� Allows further filtering of captured metrics

• Can be enabled server level or session level

� Server level via sp_configure

� Session level via ‘set metrics_capture’

Page 7: er

Query Plan Metrics SyntaxQuery Plan Metrics Syntax

• SyntaxServer - sp_configure “enable metrics capture”, 1

Session - set metrics_capture on/off

sp_metrics [flush | backup | drop | help], @arg1 [, @arg2]

• Accessing

7 – © 2011 Sybase, Inc – May 3, 2011

• Accessing

� QP metrics are captured in default “running” group� gid = 1

� Move to different group with sp_metrics ‘backup’� More on sp_metrics on later slides

� View with sysquerymetrics view� Each db has it’s own sysquerymetrics

– Built on <db>..sysqueryplans

Page 8: er

sysquerymetrics view sysquerymetrics view -- ColumnsColumns

Field Definition

uid User IDgid Group IDhashkey The hashkey over the SQL query textid Unique IDsequence Sequence number for a row when multiple rows are

required for the SQL text exec_min Minimum execution timeexec_max Maximum execution timeexec_avg Average execution time

Sorts gone amok

8 – © 2011 Sybase, Inc – May 3, 2011

exec_avg Average execution timeelap_min Minimum elapsed timeelap_max Maximum elapsed timeelap_avg Average elapsed timelio_min Minimum logical IOlio_max Maximum logical IOlio_avg Average logical IOpio_min Minumum physical IOpio_max Maximum physical IOpio_avg Average physical IOcnt Number of times the query has been executed.abort_cnt Number of times a query was aborted by Resource

Governor as a resource limit was exceeded.qtext query text

Bad QP or QEXEC

Page 9: er

How to Limit What is Captured (3 Ways)How to Limit What is Captured (3 Ways)

• Use sp_configure to set thresholds

� enable metrics capture = DEFAULT (1)

� metrics lio max = DEFAULT

� metrics pio max = DEFAULT

� metrics elap max = 2000

� metrics exec max = DEFAULT (1000)

• Use login trigger with ‘set metrics_capture’

� If number of users and query volume would be too high, in addition to the

9 – © 2011 Sybase, Inc – May 3, 2011

� If number of users and query volume would be too high, in addition to the filters, you should consider using a login trigger and only enable metrics capture on some number sessions

� Use sysprocesses attributes such as application name or mod of SPID as mechanism to know which users to limit the collection to.

• Use multiple narrow capture windows

� Run consecutive 10 or 15 minute metrics capture

� Filter results using sp_metrics ‘filter’

� Backup results to a new group # using sp_metrics ‘backup’

� Start next capture period

Page 10: er

sp_metrics Commandssp_metrics Commands

• help ���� sp_metrics ‘help’

� get help on a command

• flush ���� sp_metrics ‘flush’

� flush all metrics from memory to system tables

� What memory? Proc cache of course!!!

• backup ���� sp_metrics ‘backup’, ‘6’

� move the metrics in the default group to a backup group

� @arg1 is an int in char form representing group #

10 – © 2011 Sybase, Inc – May 3, 2011

� @arg1 is an int in char form representing group #

� Must be higher than 1 (1 is always current group)

• drop ���� sp_metrics ‘drop’, ‘2’

� drop a metric ID or a group of metrics

� @arg1 is an int in char form representing the first metrics group to drop in the range (must be a valid group)

• Filter ���� sp_metrics ‘filter’, ‘1’, ‘lio_max < 100’

� @arg1 is an int in char form representing the group #

� @arg2 is the predicate to apply

Page 11: er

After the Collection….Use sp_metricsAfter the Collection….Use sp_metrics

• ‘flush’ to flush all the stats to disk

• ‘backup’ to a new group

� to keep around for regression testing

• ‘filter’ to remove noise

� Works in reverse, so sp_metrics ‘filter’, <gid>, ‘lio_max < 100’ removes

everything with less than 100 logical IOs

11 – © 2011 Sybase, Inc – May 3, 2011

everything with less than 100 logical IOs

� Generally recommend only one filter set via sp_configure - so this

technique is how to apply a second filter� exec sp_configure ‘metrics elap max’, 2000

� exec sp_metrics ‘filter’,’1’,’exec_avg < 500’

� Result: anything that takes more than 2 secs elapsed and more than 500ms cpu

time

Page 12: er

Typical runTypical run

• Enable metrics captureset metrics_capture on

set statement_cache on

set literal_autoparam on

sp_configure ‘metrics elap max’, <number>

• Run test/application

• Flush/backup metrics & disable

Optional: Allows us to compare

plans/queries without worrying if

SARGS match

12 – © 2011 Sybase, Inc – May 3, 2011

• Flush/backup metrics & disablesp_metrics ‘flush’

sp_metrics ‘backup’, ‘<number>’

set metrics_capture off

• Analyzeselect * from sysquerymetrics …

sp_metrics ‘filter’, … --remove unwanted results

• Dropsp_metrics ‘drop’, ‘<number>’

Note that the # is quoted

Page 13: er

Analyzing QP MetricsAnalyzing QP Metrics

• Pretty flexible by using normal SQL on view

• Some examples:

� Find high incidence queries firstselect * from sysquerymetrics where gid=-1*<gid>order by cnt desc, elap_avg desc, hashkey, id, sequence

� Compare the metrics for same query (regression testing)select * from sysquerymetrics m1, sysquerymetrics m2where m1.hashkey = m2.hashkeyand m1.gid != m2.gid

13 – © 2011 Sybase, Inc – May 3, 2011

and m1.gid != m2.gidand m1.sequence = m2.sequence

order by m1.hashkey, gid, m1.uniqueid, m1.sequence

• Some tips:

� Sort metrics by total LIO or total elapsed by muliplying cnt*lio_avg or similar - helps to balance repeat bad queries vs. the one odd execution that happens only once per day

� Select a list of known approved query hashkeys (e.g. report queries) into a table and then only select queries not in that list to eliminate queries that you know legitimately exceed the desired limit

Page 14: er

Quick Review of AdQuick Review of Ad--hoc Query Detectionhoc Query Detection

• Start with MDA to determine if long running query is cause

� monSysStatement and monProcessStatement

• Dev/Test

� Enable QP metrics capture globally with decreasing filters on elapsed time

� Fix the obvious problems (missing stats, etc.)

� Consider login trigger to change optgoal or set/disable opt criteria

14 – © 2011 Sybase, Inc – May 3, 2011

� Consider login trigger to change optgoal or set/disable opt criteria

� Use QP Tune on queries left to find out if fix is possible without rewriting the query

• Production

� Crisis mode: � Use QP metrics as above to try to isolate critical problems/queries� Enable/disable quickly to avoid needle in haystack problem

� Post-upgrade monitoring:� Use a login trigger and ‘set metrics_capture on’ for a representative set of users.

Page 15: er

What is QP Tune?What is QP Tune?

• A Tuning Utility for Semi-Automating some of the Tuning Steps

� Can identify and fix missing statistics

� Core features are query capture and metrics comparison

• Based on QP Metrics

� It locates query issues via QP Metrics/sysquerymetrics

� As a result, it might not work well on store procs/statement cache

� Locates missing statistics via sp_configure

15 – © 2011 Sybase, Inc – May 3, 2011

• Focus is on query capture/metrics comparison

� Unfortunately, you get to test your meddle with supplying optgoals/criteria to try

� …and executing the iterations to try

� Generates abstract query plan for QPOD

� Compares results and tells you which ones worked better � Arguably, the main feature

• Requires sa_role or sso_role for capture/fix

� Other users can only do compare

� Why? Because QP Tune exec’s sp_configure

Page 16: er

QP Tune SyntaxQP Tune Syntax

• Location

� $SYBASE/ASE-15_0/qptune

• Syntax

� QPTune� [-U <username>] [-P <password>] [-S <hostname:port/database>] [-J <charset>] � [-A <action [start|collect(_full)|compare|fix|(start|collect|fix|undo_fix)_stats]>]� [-M <mode>] � [-T <appTime>]

16 – © 2011 Sybase, Inc – May 3, 2011

� [-T <appTime>] � [-i <inputFile>]� [-o <outputFile>] � [-f <fileList(,)>]� [-c <configFile>]� [-l <limit>]� [-e <evalField>] � [-d <diff%(,diff_abs)>]� [-m <missingCount>]� [-n <login>] � [-N (noexec)]� [-g (applyOptgoal)]� [-v (verbose)] [-s (sort)] [-h (help)]

Page 17: er

Using QP Tune….Using QP Tune….

• VERY IMPORTANT

� Download/read ASE 15.0.3 Migration Technology Guide � Chapter 2 - QP Tune

• Can it be used in production?

� Possibly - but think about it…� it may be making server changes that affect everything and in addition repeatedly

reissuing queries with known issues - artificially inflating CPU costs, IO patterns and data cache utilization

� …and really high usage of system segment/sysquery plans

17 – © 2011 Sybase, Inc – May 3, 2011

� …and really high usage of system segment/sysquery plans� …and if app changes data with insert/update/delete….did you book that trade 20

times??

• Recommendation

� Use QP Metrics/MDA to find queries with issues in production

� Run QP Tune on just those queries in DEV/QA

� Determine how you are going to fix each query

� Deploy fixes to PROD manually� Either by copying AQP created by QP Tune to PROD� …making suggested optgoal/criteria changes in login trigger� …making suggested config changes to PROD server

Page 18: er

The Need for Application TracingThe Need for Application Tracing

• During development

� Frequently the developer hits a query issue � Fun job of finding which query is the cause….

� …then has to extract the SQL, application testing values

� DBA attempts to reproduce� Sometimes hindered by not having same environment

• During production

18 – © 2011 Sybase, Inc – May 3, 2011

• During production

� Hard to identify the exact query being run by the user at the point in

time� Most techniques do server wide capturing for all processes (MDA)

� Diagnostic traces require submitting ‘set options’ ahead of SQL – difficult to modify application to do so

– Even more difficult to capture the output

Page 19: er

Applicating Tracing: 'set tracefile' (15.0.2)Applicating Tracing: 'set tracefile' (15.0.2)

• set tracefile { filepath | off } [ for spid ]� Saves all SQL text to a flat file until turned off

� Session tracing is enabled for the spid/session being traced….� ….it is not the perspective that the sa session is tracing a spid, but rather that a spid is

being traced

� Restrictions� You cannot save the SQL text for system tasks (housekeeper, checkpoint process, etc.).� You must have the sa or sso roles, or be granted set tracing permission� set tracefile is not allowed to open an existing file as a tracefile.� During an SA or SSO session, if you enable set tracfile for a specific spid, all subsequent

19 – © 2011 Sybase, Inc – May 3, 2011

� During an SA or SSO session, if you enable set tracfile for a specific spid, all subsequent tracing commands executed take effect on that spid, not the SA or SSO spid.

� You cannot trace more than one session at a time from a single sa or sso session. � You cannot trace the same session from multiple sa or sso sessions.

� Notes� The file storing the trace output is closed when the session being traced quits or when

you disable tracing.� Before you allocate resources for tracing, keep in mind that each tracing requires one file

descriptor per engine.

• sp_helpapptrace

� System proc that reports sessions being traced and the session doing the tracing

Page 20: er

sp_helpapptracesp_helpapptrace

20 – © 2011 Sybase, Inc – May 3, 2011

Page 21: er

set tracefile & set optionsset tracefile & set options

• Tracing a session

� Once you have enabled tracing for a session, any further set commands associated with QP debugging take effect for the session being traced vs. the session issuing the commands

• Set options that affect tracing

� set show_sqltext [on | off] (requires trace flag 3604 to be on)

� set showplan [on | off]

� set statistics io, time, plancost, resource [on | off]

� set option show [normal | brief | long | on | off]

� set option show_lop [normal | brief | long | on | off]

21 – © 2011 Sybase, Inc – May 3, 2011

� set option show_parallel [normal | brief | long | on | off]

� set option show_search_engine [normal | brief | long | on | off]

� set option show_counters [normal | brief | long | on | off]

� set option show_managers [normal | brief | long | on | off]

� set option show_histograms [normal | brief | long | on | off]

� set option show_abstract_plan [normal | brief | long | on | off]

� set option show_best_plan [normal | brief | long | on | off]

� set option show_code_gen [normal | brief | long | on | off]

� set option show_pio_costing [normal | brief | long | on | off]

� set option show_lio_costing [normal | brief | long | on | off]

� set option show_log_props [normal | brief | long | on | off]

� set option show_elimination [normal | brief | long | on | off]

� set option show_missing_stats [normal | brief | long | on | off]

Page 22: er

Using Application TracingUsing Application Tracing

• Scenario

� Fred calls up complaining of a slow query

• Steps for Application Tracing

� Use sp_who to find Fred’s spid (e.g. 123)

� set tracefile '/home/sybase/my_tracetest_20100914.out' for 123

� Enable desired options� Dbcc traceon(3604)

22 – © 2011 Sybase, Inc – May 3, 2011

� Dbcc traceon(3604)� Set show_sqltext on� Set showplan on� Set statistics time, io on� Set statistics plancost, resource on� Set option show_missing_stats on� Set option show on -- optional

� Check tracing (sp_helpapptrace)

� (run test)

� set tracefile off for 123

Page 23: er

Sample tracefile outputSample tracefile output

(some output omitted for brevity)

2010/09/14 16:33:22.80

SQL Text: select *

into #temp

from telco_facts

where number_of_lines > 1

==================== Lava Operator Tree ====================

Emit

(VA = 2)

r:3.665e+06 er:2.376e+06

cpu: 10300

/

Insert

#temp

23 – © 2011 Sybase, Inc – May 3, 2011

#temp

(VA = 1)

r:3.665e+06 er:2.376e+06

/

TableScan

telco_facts

(VA = 0)

r:3.665e+06 er:2.376e+06

l:1.029e+05 el:0

p:1.029e+05 ep:0

============================================================

Table: telco_facts scan count 1, logical reads: (regular=102858 apf=0 total=102858), physical reads: (regular=21509 apf=81349 total=102858), apf IOs used=81349

Table: #temp00001110015196818 scan count 0, logical reads: (regular=3671702 apf=0 total=3671702), physical reads: (regular=0 apf=0 total=0), apf IOs used=0

Total writes for this command: 407

Execution Time 103.

Page 24: er

Analyzing QP Optimization

24 – Sybase Confidential – May 3, 2011

Page 25: er

Tools for Analyzing QP OptimizationTools for Analyzing QP Optimization

• Old tools (ASE 12.5 and previous)

� Set showplan

� Set statistics time, io

� Dbcc traceon (302, 310, 311, …)

• New tools

� Enhanced showplan (join strategy, sorts, etc.)

� Set option show (replaces dbcc traces - now deprecated)

� Capture missing statistics

25 – © 2011 Sybase, Inc – May 3, 2011

� Capture missing statistics

� Set statistics plancost, resource

• What TS will need (so you might as well use as well)

� Showplan, set statistics plancost

� Set option show

� Schema, optdiag, data (if possible)

• You will need to take more care in testing

� Having statement cache enabled can be frustrated during testing as it may grab a previously cached good/bad plan….

� Showplan will reveal if using a previously cached plan

Page 26: er

Example: Multiple Join KeysExample: Multiple Join Keys

• Sample SQL:select count(*)

from tableA, tableB

where tableA.TranID = tableB.TranID

and tableA.OriginCode = tableB.OriginCode

and tableB.Status <> ‘Y’

• Comments:

26 – © 2011 Sybase, Inc – May 3, 2011

• Comments:

� Since tableA doesn’t have any SARG conditions, the entire table is

likely required - and a table scan would be expected.

� Assuming a normal pkey/fkey relationship, however, we would expect

tableB to use the index on the fkey relationship {TranID, OriginCode}.

� If most Status values in TableB are not ‘Y’, having column statistics

might help - even if column not indexed

Page 27: er

Showplan: Multiple Join KeysShowplan: Multiple Join Keys

The type of query is SELECT.

ROOT:EMIT Operator

|SCALAR AGGREGATE Operator

| Evaluate Ungrouped COUNT AGGREGATE.

|

| |MERGE JOIN Operator (Join Type: Inner Join)

| | Using Worktable2 for internal storage.

| | Key Count: 1

| | Key Ordering: ASC

| |

| | |SCAN Operator

| | | FROM TABLE

| | | tableB

| | | Table Scan.

Actual key count should have been 2

since join is on both TranID and

OriginCode. This is a key clue that

update index statistics needs to be

run.

27 – © 2011 Sybase, Inc – May 3, 2011

| | | Table Scan.

| | | Forward Scan.

| | | Positioning at start of table.

| | | Using I/O Size 16 Kbytes for data pages.

| | | With LRU Buffer Replacement Strategy for data pages.

| |

| | |SORT Operator

| | | Using Worktable1 for internal storage.

| | |

| | | |SCAN Operator

| | | | FROM TABLE

| | | | tableA

| | | | Table Scan.

| | | | Forward Scan.

| | | | Positioning at start of table.

| | | | Using I/O Size 16 Kbytes for data pages.

| | | | With LRU Buffer Replacement Strategy for data pages.

Since TableB is bigger and we have to scan

it, we make it the outer table….this means

we sort the smaller table - but it is still a

sort. In this case a clustered index on

TableA may have been all that was

necessary to turn a SMJ into a MJ (faster

than NLJ)

Page 28: er

Set option show….Set option show….

• set option show <normal/brief/long/on/off>

� Basic syntax common to all

� Execute this one first prior to any of the below when used together (other

wise it will reset the below to the level of detail for show command itself)

• Common ones used (full list is in the documentation)

� … show Shows all the details (TS will want this one)

� … show_abstract_plan <…> Shows the details of an abstract plan.

28 – © 2011 Sybase, Inc – May 3, 2011

� … show_abstract_plan <…> Shows the details of an abstract plan.

� … show_search_engine <…> Shows the details of a search engine.

� … show_best_plan <…> Shows the details of the best QP plan.

� … show_code_gen <…> Shows the details of code generation.

� … show_pio_costing <…> Shows estimates of physical I/O

� … show_lio_costing <…> Shows estimates of logical input/output.

� … show_elimination <…> Shows partition elimination.

� … show_missing_stats <…> Shows columns with missing stats.

Page 29: er

For example…For example…

• We want to…

� See the query plan

� …make sure we aren’t missing obvious statistics

� …get the abstract plan � so we can do a ‘create plan’ and fix the app w/o changing codeset showplan on

set option show_missing_stats on

29 – © 2011 Sybase, Inc – May 3, 2011

set option show_missing_stats on

set option show_abstract_plan on

• We want to…debug index & hordes of detail

� Like we used to with 302,310,315,317, etc.dbcc traceon(3604)

set showplan on

set option show long

Page 30: er

Histograms and ASE 15Histograms and ASE 15

• ASE 15 is much more susceptible to

� Missing histograms

� Missing indexes

• #1 Cause for issues

� Forgetting to first delete statistics and then run update index statistics on all tables after upgrading (part of the TS checklist)

• Rationale

� In ASE 12.5, we often only had a single technique for performing certain

30 – © 2011 Sybase, Inc – May 3, 2011

� In ASE 12.5, we often only had a single technique for performing certain operations - such as joins, distincts, unions, etc.

� ASE 15 often now has 2-3 methods for any one of these� The decision as to which one is best to use will often depend upon the estimate for

query costing� If we don’t have any histograms on the SARGs/Joins/Distincts, we will be forced to use

the “magic values”…true in 12.x - still true in 15.x– There are more “magic” values than just the 10%/25%/33% for SARGS– “magic” values are also used for joins (i.e. equijoin translates to 10%)– “magic” values for distincts often used 256*datatype length

� As database volumes have grown, these large percentages for magic values often translates into really high estimates for LIO, PIO or CPU

� Result is that ASE will often pick a DSS type technique for processing large volumes of data instead of an OLTP technique

Page 31: er

Finding Missing HistogramsFinding Missing Histograms

• New Config in ASE 15.0.3 ESD #1

� sp_configure ‘capture missing statistics’, [0 | 1]

� In pre-15.0.3, similar functionality with set option show_missing_stats on, but output has to be grabbed/grep'd from ASE errorlog

• Used by QP Tune

� Problem: QP Tune is not recommended for production� Okay for stats, but then you have to remember not to use it for queries - best bet is not to use it

for production at all

� Solution: Analyze sysstatistics directly

31 – © 2011 Sybase, Inc – May 3, 2011

� Solution: Analyze sysstatistics directly� Config option is dynamic - turn on, sample, turn off

• sysstatistics

� formatid = 110

� colidarray � the columns without stats� One row for each column without statistics (column stats)� One row for each combination of columns without statistics (density stats)

– But colidarray may only list the first two columns

� Can easily be decoded with a SQL function; see blog at http://tinyurl.com/3sop2dj

� Column 'C0' � number of times column referenced without stats

Page 32: er

Missing Stats in SysstatisticsMissing Stats in Sysstatistics

32 – © 2011 Sybase, Inc – May 3, 2011

Page 33: er

Identify Missing StatisticsIdentify Missing Statistics

• Syntaxsp_configure ‘capture missing statistics’, [0 | 1]

set option show_missing_stats on

• Has been really useful in identifying statistics & indexing issues

� Limited to missing statistics, vs. pointing out when not enough statistics

steps or stale statistics exists….but…

� Used extensively internally on customer repro's

33 – © 2011 Sybase, Inc – May 3, 2011

� Helps point out when adding statistics on some columns that statistics are

currently not available for may help� Consider difference between update statistics and update index statistics

� May point out when skewed low cardinality columns need stats even when not indexed

for queries looking for the low incidence values– E.g. if we have stats on the column “is_color_blind=‘Y’”, the optimizer can make a better choice

about which table to join in which order as it knows number of rows qualifying

• Useful for identifying missing indexes

� Missing statistics � missing single column indexes

� Missing density stats � missing composite column indexes

Page 34: er

Let’s Take An Example (purge delete):Let’s Take An Example (purge delete):

delete margin_activity_fin

from margin_activity ma,

margin_activity_fin maf

where ma.ssb_fund = 'IVX6'

and ma.margin_date = '20100601'

and ma.transaction_type <> 'ADJ CASH'

and maf.ssb_fund = ma.ssb_fund

and maf.margin_date = ma.margin_date

and maf.opening_trade_id = ma.opening_trade_id

and isnull (maf.closing_trade_id, 'OPEN') = isnull (ma.closing_trade_id, 'OPEN')

and not exists (select * from margin_approval_summ

34 – © 2011 Sybase, Inc – May 3, 2011

and not exists (select * from margin_approval_summ

where appr_key1_value = ma.ssb_fund

and appr_key2_value = ma.settle_currency

and appr_key5_value = ma.clearing_broker_nbr

and margin_date = ma.margin_date

and ((transaction_type <> 'ADJ CASH' and approved_flg = 'Y')

or cash_flg = 'C‘

)

)

Page 35: er

Resulting Ugly Query PlanResulting Ugly Query PlanSTEP 1

The type of query is DELETE.

10 operator(s) under root

|ROOT:EMIT Operator (VA = 10)

|

| |DELETE Operator (VA = 9)

| | The update mode is deferred.

| |

| | |SQFILTER Operator (VA = 8) has 2 children.

| | |

| | | |MERGE JOIN Operator (Join Type: Inner Join) (VA = 4)

| | | | Using Worktable1 for internal storage.

| | | | Key Count: 1

| | | | Key Ordering: ASC

| | | |

| | | | |RESTRICT Operator (VA = 1)(0)(0)(0)(0)(3)

| | | | |

| | | | | |SCAN Operator (VA = 0)

| | | | | | FROM TABLE

| | | | | | Keys are:

| | | | | | ssb_fund ASC

| | | | | | margin_date ASC

| | | | | | Using I/O Size 2 Kbytes for index leaf pages.

| | | | | | With LRU Buffer Replacement Strategy for index leaf pages.

| | | | | | Using I/O Size 16 Kbytes for data pages.

| | | | | | With LRU Buffer Replacement Strategy for data pages.

| | |

| | | Run subquery 1 (at nesting level 1).

| | |

| | | QUERY PLAN FOR SUBQUERY 1 (at nesting level 1 and at line 10).

| | |

| | | Correlated Subquery.

| | | Subquery under an EXISTS predicate.

| | |

| | | |SCALAR AGGREGATE Operator (VA = 7)

| | | | Evaluate Ungrouped ANY AGGREGATE.

| | | | Scanning only up to the first qualifying row.

| | | |

| | | | |RESTRICT Operator (VA = 6)(0)(0)(0)(10)(0)

35 – © 2011 Sybase, Inc – May 3, 2011

| | | | | | FROM TABLE

| | | | | | margin_activity_fin

| | | | | | maf

| | | | | | Using Clustered Index.

| | | | | | Index : margin_activity_fin_key

| | | | | | Forward Scan.

| | | | | | Positioning by key.

| | | | | | Keys are:

| | | | | | ssb_fund ASC

| | | | | | margin_date ASC

| | | | | | Using I/O Size 2 Kbytes for index leaf pages.

| | | | | | With LRU Buffer Replacement Strategy for index leaf pages.

| | | | | | Using I/O Size 16 Kbytes for data pages.

| | | | | | With LRU Buffer Replacement Strategy for data pages.

| | | |

| | | | |RESTRICT Operator (VA = 3)(0)(0)(0)(0)(3)

| | | | |

| | | | | |SCAN Operator (VA = 2)

| | | | | | FROM TABLE

| | | | | | margin_activity

| | | | | | Using Clustered Index.

| | | | | | Index : pkey

| | | | | | Forward Scan.

| | | | | | Positioning by key.

| | | | |RESTRICT Operator (VA = 6)(0)(0)(0)(10)(0)

| | | | |

| | | | | |SCAN Operator (VA = 5)

| | | | | | FROM TABLE

| | | | | | margin_approval_summ

| | | | | | Using Clustered Index.

| | | | | | Index : ix1

| | | | | | Forward Scan.

| | | | | | Positioning by key.

| | | | | | Keys are:

| | | | | | appr_key1_value ASC

| | | | | | margin_date ASC

| | | | | | appr_key2_value ASC

| | | | | | Using I/O Size 2 Kbytes for index leaf pages.

| | | | | | With LRU Buffer Replacement Strategy for index leaf pages.

| | | | | | Using I/O Size 16 Kbytes for data pages.

| | | | | | With LRU Buffer Replacement Strategy for data pages.

| | |

| | | END OF QUERY PLAN FOR SUBQUERY 1.

| |

| | TO TABLE

| | margin_activity_fin

| | Using I/O Size 2 Kbytes for data pages.

Page 36: er

Why Was It Ugly???Why Was It Ugly???

• Problems

� Merge join on 1 key column of multiple column join is a real tip off

that statistics are missing or join is not a real equijoin

� It appeared to pick a incompletely indexed join on subquery� Subquery correlation on

– {appr_key1_value, appr_key2_value, appr_key5_value, margin_date}

� Indexed columns were only on – {appr_key1_value, margin_date , appr_key2_value}

36 – © 2011 Sybase, Inc – May 3, 2011

– {appr_key1_value, margin_date , appr_key2_value}

• Results of show_missing_statsNO STATS on column margin_activity_fin.opening_trade_id

NO STATS on column margin_activity_fin.margin_date

NO STATS on column margin_activity.transaction_type

NO STATS on column margin_approval_summ.cash_flg

NO STATS on column margin_approval_summ.approved_flg

NO STATS on column margin_approval_summ.transaction_type

NO STATS on column margin_approval_summ.appr_key5_value

NO STATS on density set for margin_approval_summ={margin_date, appr_key5_value,

appr_key2_value, appr_key1_value}

NO STATS on density set for margin_activity={clearing_broker_nbr, settle_currency,

margin_date, ssb_fund}

NO STATS on density set for margin_activity={clearing_broker_nbr, settle_currency}

Page 37: er

Let’s Break It Down (1)Let’s Break It Down (1)

• All those “flag” columns in subqueryNO STATS on column margin_approval_summ.cash_flg

NO STATS on column margin_approval_summ.approved_flg

NO STATS on column margin_approval_summ.transaction_type

• But are the stats really missing???

� These are low cardinality columns - having an index likely will not help

� However, the question is how many of the otherwise qualified rows in

the join would be disqualified by these “flags”

37 – © 2011 Sybase, Inc – May 3, 2011

the join would be disqualified by these “flags”� Is any one of these values or the combination of them fairly discrete enough that it

would reduce the rows that qualify for the join to just a small percentage

� If so, while an index may not be beneficial, having column stats may be– And you may not need to update those column stats that often if the relative ratio of

statistics skew stays the same….just update on a less periodic basis

Page 38: er

Let’s Break It Down (2)Let’s Break It Down (2)

• A much bigger problemNO STATS on column margin_activity_fin.opening_trade_id

NO STATS on column margin_activity_fin.margin_date

NO STATS on column margin_activity.transaction_type

• These are 2 of the 4 join columns for outer query

� Plus one of the SARGS - likely low cardinality

� But from the join perspective, remember, one of the join conditions

was isnull (maf.closing_trade_id, 'OPEN') = isnull (ma.closing_trade_id,

38 – © 2011 Sybase, Inc – May 3, 2011

was isnull (maf.closing_trade_id, 'OPEN') = isnull (ma.closing_trade_id,

'OPEN')� Unless you had a functional index, not a valid SARG or useful for join optimization

� Probably should have been written as a UNION ALL

� Regardless - this means for the join, we will only use the stats on the

leading column in the index because that is what we have� For the rest of the join conditions (2 cols above) we will use magic number of 10%

in combination with range density to try to get an estimate….but…..

� …hence the MERGE join with 1 column key

Page 39: er

Let’s Break It Down (3)Let’s Break It Down (3)

• Possible Indexing IssuesNO STATS on column margin_approval_summ.appr_key5_value

NO STATS on density set for margin_approval_summ={margin_date, appr_key5_value,

appr_key2_value, appr_key1_value}

NO STATS on density set for margin_activity={clearing_broker_nbr, settle_currency,

margin_date, ssb_fund}

NO STATS on density set for margin_activity={clearing_broker_nbr, settle_currency}

• All point to possible indexing issues with subquery

� First two are pointing out that appr_key5_value is missing from the

39 – © 2011 Sybase, Inc – May 3, 2011

� First two are pointing out that appr_key5_value is missing from the

index on the subquery table

� The next two point out that while there are stats on the individual

columns, there isn’t an index that helps correlate the outer query with

the subquery� If there columns weren’t indexed at all or had missing stats, we would see

individual missing stats on the specified columns - which we don’t…so there are

stats

� But since we don’t have stats on the combination of columns, that means there

isn’t a covering index since density stats are created with an index (and updated

when update statistics is run)

Page 40: er

set statistics plancost/resourceset statistics plancost/resource

• Adding an index or column stats may avoid a query rewrite

• Use statistics plancost to find out where

� Look for abnormally high row estimates 2 orders of magnitude higher than next higher node when reduction not due to aggregation/distinct

� Look for sorts where estimated/actual rows exceed ‘lava buffers per operator’ as it likely spills to disk (see physical IOs on node)� Focus on ‘buf ct’ and p/ep stats

� Focus on trying to get the row estimates as accurate as possible as low in

40 – © 2011 Sybase, Inc – May 3, 2011

� Focus on trying to get the row estimates as accurate as possible as low in the tree as possible

� Stats or indexes on low cardinality columns actually may be useful in ASE 15.0.x - especially due to frequency cells (histogram tuning)

• Use set statistics resource

� Look for high proc cache usage. If no sorting, number of histograms may be too high - slowing query optimization

� Correlate tempdb hwm with nodes - if you can’t - likely is worktable� High tempdb = sorts or worktable� Large worktable � unindexed join later - most likely becomes a SMJ.

Page 41: er

set statistics plancost onset statistics plancost on

Emit(VA = 7)12 rows est: 1200cpu: 500

/GroupSorted(VA = 6)12 rows est: 1200

/NestLoopJoinInner Join(VA = 5)242704 rows est: 244857

Query:

select S.service_key, M.year, M.fiscal_period,count(*)

from telco_facts T,month M, service S

where T.month_key=M.month_key

and T.service_key = S.service_key

and S.call_waiting_flag='Y'

and S.caller_id_flag='Y'

and S.voice_mail_flag='Y'

group by M.year, M.fiscal_period, S.service_key

order by M.year, M.fiscal_period, S.service_key

go

41 – © 2011 Sybase, Inc – May 3, 2011

/ \Sort IndexScan(VA = 3) month_svc_idx (T)72 rows est: 24 (VA = 4)lio: 6 est: 6 242704 rows est: 244857pio: 0 est: 0 lio: 1116 est: 0cpu: 0 bufct: 16 pio: 0 est: 0

/NestLoopJoinInner Join(VA = 2)72 rows est: 24

/ \TableScan TableScanmonth (M) service (S)(VA = 0) (VA = 1)24 rows est: 24 72 rows est: 24lio: 1 est: 0 lio: 24 est: 0pio: 0 est: 0 pio: 0 est: 0

Page 42: er

set statistics resource on set statistics resource on

• set statistics resource { on | off }

� Shows compilation and execution resources used� Tempdb, proc cache, sorting, etc….

• Example:

42 – © 2011 Sybase, Inc – May 3, 2011

• Example:

Statement: 1 Compile time resource usage: (est worker

processes=0 proccache=81), Execution time resource

usage: (worker processes=0 auxsdesc=0 plansize=10

proccache=15 proccache hwm=21 tempdb hwm=2)

Private buffer count: 24,Private HWM buffer count: 24

Page 43: er

Manually Tuning Queries

43 – Sybase Confidential – May 3, 2011

Page 44: er

Tools for Manually Tuning OptimizationTools for Manually Tuning Optimization

• Queries impacted due to optimization time

� Enable statement cache + literal autoparameterization

� Reduce optimization time

� Disable procedure deferred compilation

• Queries impacted due to resource usage

� Histogram tuning

44 – © 2011 Sybase, Inc – May 3, 2011

� Histogram tuning

� Server configuration settings

• Queries impacted due to plan changes

� Query rewrite (stored procs) (especially if bad SQL)

� Set statistics plancost

� Optgoals & controls

� Abstract Query Plans

Page 45: er

A Commonly Reported Issue:A Commonly Reported Issue:

From: [email protected] [mailto:[email protected]]

Sent: Wednesday, April 15, 2009 11:27 AM

To: [email protected]; [email protected]

Subject: Case # 1152#### in TS-NA-FAST queue. This is a P3 / System Not Down ASE 15.x case

Message from ClaSS!

Case # 1152#### has been dispatched/forwarded to the TS-NA-FAST queue.

This is a P3 / System Not Down case

45 – © 2011 Sybase, Inc – May 3, 2011

This is a P3 / System Not Down case

Site Name: (customer name redacted)

Case Description : We have a sql code that is using a table with more than 1 million rows. The table

has several indexes, but the optimizer is doing a full table scan instead of using the indexes. Can

you please help.

Adaptive Server Enterprise/15.0.2/EBF 15959 ESD#6/P/

Page 46: er

A Commonly Reported Issue…Uh OhA Commonly Reported Issue…Uh Oh

• Assumption: Query is slower (it doesn’t state this)

� If just worried about table scan, MJ and HJ may do table scans

� ….so table scans are not necessarily the ‘evil’ they were in 12.x

• Most likely cause

� Customer forgot to run update index statistics� Yes, there are other likely causes - but this is the most common

46 – © 2011 Sybase, Inc – May 3, 2011

� Result is that ASE is picking a merge join� Maybe because this is the best option anyhow (assume not)

� Because of the time involved, it likely is sorting after the table scan

• What customer needs to do

� Besides the missing histograms…..

� Learn what needs to be collected for query performance issues

� See if the table scan is really an issue…� We will assume it is or else they would not have called TS….

Page 47: er

Merge Join

• What is it– Alternating scans of outer and inner

tables, matching rows in the process

– Scans each row in outer and inner table once

– Requires that outer and inner inputs are sorted in join key order (i.e. the join columns should be indexed)

• Query Tip

47 – © 2011 Sybase, Inc – May 3, 2011

• Query Tip– If you see this in a bad query plan, a

possible cause is lack of statistics on 2nd � nth join column� Update index statistics

– Most likely will be seen when two temp tables are joined (allrows_mixed)

– Watch for sorts….no-sort MJ likely not a problem

Page 48: er

Merge Joins w/ NonMerge Joins w/ Non--Selective PredicatesSelective Predicates

• Indexed or Not

• Sample Queries

� pubtune database (salesdetail with ~1.3M rows)

� Query (37 row result)select stores.stor_name, stores.city, sales.date,

salesdetail.title_id, salesdetail.qty, salesdetail.discount

from stores, sales, salesdetail

48 – © 2011 Sybase, Inc – May 3, 2011

from stores, sales, salesdetail

where stores.stor_id = sales.stor_id

and sales.stor_id=salesdetail.stor_id

and sales.ord_num=salesdetail.ord_num

and salesdetail.discount > 50

Page 49: er

The The ShowplansShowplans (allrows_mix vs. (allrows_mix vs. oltpoltp))

|ROOT:EMIT Operator (VA = 7)

|

| |MERGE JOIN Operator (Join Type: Inner Join) (VA = 6)

| | Using Worktable4 for internal storage.

| | Key Count: 2

| | Key Ordering: ASC ASC

| |

| | |MERGE JOIN Operator (Join Type: Inner Join) (VA = 3)

| | | Using Worktable2 for internal storage.

| | | Key Count: 1

| | | Key Ordering: ASC

| | |

| | | |SCAN Operator (VA = 0)

| | | | FROM TABLE

| | | | sales

| | | | Table Scan.

| | | | Forward Scan.

| | | | Positioning at start of table.

| | | | Using I/O Size 32 Kbytes for data pages.

| | | | With LRU Buffer Replacement Strategy for data pages.

|ROOT:EMIT Operator (VA = 4)

|

| |N-ARY NESTED LOOP JOIN Operator (VA = 3) has 3 children.

| |

| | |SCAN Operator (VA = 0)

| | | FROM TABLE

| | | stores

| | | Table Scan.

| | | Forward Scan.

| | | Positioning at start of table.

| | | Using I/O Size 32 Kbytes for data pages.

| | | With LRU Buffer Replacement Strategy for data pages.

| |

| | |SCAN Operator (VA = 1)

| | | FROM TABLE

| | | sales

| | | Using Clustered Index.

| | | Index : salesind

| | | Forward Scan.

| | | Positioning by key.

49 – © 2011 Sybase, Inc – May 3, 2011

| | | | With LRU Buffer Replacement Strategy for data pages.

| | |

| | | |SORT Operator (VA = 2)

| | | | Average Row width is 42.394478

| | | | Using Worktable1 for internal storage.

| | | |

| | | | |SCAN Operator (VA = 1)

| | | | | FROM TABLE

| | | | | stores

| | | | | Table Scan.

| | | | | Forward Scan.

| | | | | Positioning at start of table.

| | | | | Using I/O Size 32 Kbytes for data pages.

| | | | | With LRU Buffer Replacement Strategy for data pages.

| |

| | |SORT Operator (VA = 5)

| | | Average Row width is 37.544621

| | | Using Worktable3 for internal storage.

| | |

| | | |SCAN Operator (VA = 4)

| | | | FROM TABLE

| | | | salesdetail

| | | | Table Scan.

| | | | Forward Scan.

| | | | Positioning at start of table.

| | | | Using I/O Size 32 Kbytes for data pages.

| | | | With MRU Buffer Replacement Strategy for data pages.

| | | Positioning by key.

| | | Keys are:

| | | stor_id ASC

| | | Using I/O Size 4 Kbytes for data pages.

| | | With LRU Buffer Replacement Strategy for data pages.

| |

| | |SCAN Operator (VA = 2)

| | | FROM TABLE

| | | salesdetail

| | | Index : salesdetailind

| | | Forward Scan.

| | | Positioning by key.

| | | Keys are:

| | | stor_id ASC

| | | ord_num ASC

| | | Using I/O Size 4 Kbytes for index leaf pages.

| | | With LRU Buffer Replacement Strategy for index leaf pages.

| | | Using I/O Size 4 Kbytes for data pages.

| | | With LRU Buffer Replacement Strategy for data pages.

NLJ is looking so much better!!!NLJ is looking so much better!!!

Page 50: er

The ResultsThe Results

Query 1 NLJ SMJ ∆%

Estimated IO Cost 2,927,215 1,310,046 -55

Proc cache (opt) 78 86 10

Proc cache hwm (exec) 11 63 472

Private Buffers 0 103

Actual IO Cost 1,909,689 66,516 -96

50 – © 2011 Sybase, Inc – May 3, 2011

Actual IO Cost 1,909,689 66,516 -96

Total Writes 107 0 -100

CPU Time 15,700 100 -99

Elapsed Time 22,703 3,906 -83

Whoa Whoa -- NLJ got skunked by a Merge JoinNLJ got skunked by a Merge Join!!!!!!(even with the sorting…)(even with the sorting…)

ASE 15.0.3 ESD #1 with 8 engines and 9GB of default cache

Page 51: er

Set statistics Set statistics plancostplancost -- allrows_oltpallrows_oltp

==================== Lava Operator Tree ====================

Emit

(VA = 4)

r:32 er:439703

cpu: 15700

/

NaryNLJoin

(VA = 3)

r:32 er:439703

/ \

TableScan NaryNLJoin

51 – © 2011 Sybase, Inc – May 3, 2011

TableScan NaryNLJoin

stores (VA = 3)

(VA = 0) r:32 er:439703

r:507 er:507

l:13 el:13

p:0 ep:2

/ \

IndexScan NaryNLJoin

salesind (VA = 3)

(VA = 1) r:32 er:439703

r:132357 er:132363

l:2637 el:2128

p:15 ep:1115

/

IndexScan

salesdetailind

(VA = 2)

r:32 er:439703

l:809882 el:905313

p:11370 ep:27533

Remember, we are hitting every row in the

table for every store - so we are hitting some

pages more than once…so with 1.3M rows in

the table, if we have 2 levels of indexing, we

are doing 3 IO’s per row…”er” is based on an

unbounded range of 33%....

No SARG - every row

No SARG - every row

(l/el and p/ep stats) +

10% magic number

on 1.3M for row

estimate

Page 52: er

Set statistics Set statistics plancostplancost -- allrows_mixallrows_mix

==================== Lava Operator Tree ====================

Emit

(VA = 7)

r:32 er:439703

cpu: 100

/

MergeJoin

Inner Join

(VA = 6)

r:32 er:439703

/ \

MergeJoin Sort

Inner Join (VA = 5)

Assuming we can’t change the

query (by adding SARGS) one way

to speed up query over all is to

eliminate the sorts….clustered

index change most likely

52 – © 2011 Sybase, Inc – May 3, 2011

Inner Join (VA = 5)

(VA = 3) r:32 er:445585

r:1858 er:132363 l:6 el:4906

p:0 ep:9802

cpu: 100 bufct: 79

/ \ /

TableScan Sort TableScan

sales (VA = 2) salesdetail

(VA = 0) r:8 er:507 (VA = 4)

r:1858 er:132357 l:6 el:6 r:32 er:445585

l:16 el:1115 p:0 ep:0 l:14854 el:14854

p:0 ep:140 cpu: 0 bufct: 24 p:1470 ep:1870

/

TableScan

stores

(VA = 1)

r:507 er:507

l:13 el:13

p:0 ep:2

We had an unbounded range (discount >

50) so the row estimate is 33% of 1.3M

rows - or ~450K rows

No SARG for sales, so

estimate is based on

10% of 1.3M due to

equijoin

Page 53: er

The Indexes on The Indexes on SalesDetailSalesDetail

53 – © 2011 Sybase, Inc – May 3, 2011

Page 54: er

PlancostPlancost: Post Clustered Index Change: Post Clustered Index Change

==================== Lava Operator Tree ====================

Emit

(VA = 6)

r:32 er:439703

cpu: 100

/

MergeJoin

Inner Join

(VA = 5)

r:32 er:439703

Sort is gone - straight merge join

thanks to creating a clustered

index with the join keys as leading

columns….

54 – © 2011 Sybase, Inc – May 3, 2011

/ \

MergeJoin TableScan

Inner Join salesdetail

(VA = 3) (VA = 4)

r:1858 er:132363 r:32 er:445585

l:14365 el:14368

p:0 ep:1796

/ \

TableScan Sort

sales (VA = 2)

(VA = 0) r:8 er:507

r:1858 er:132357 l:6 el:6

l:16 el:1115 p:0 ep:0

p:0 ep:140 cpu: 0 bufct: 24

/

TableScan

stores

(VA = 1)

r:507 er:507

l:13 el:13

p:0 ep:2

No SARG for sales or stores, so we are going to table

scan stores…thankfully it is small - but can we do

better - i.e. if tablescanning, why are we doing a sort

- we should scan a clustered index for MJ vs. SMJ

Remember

these l/el

numbers!!!

Page 55: er

The Indexes on StoresThe Indexes on Stores

55 – © 2011 Sybase, Inc – May 3, 2011

Uhhh….we are joining on stor_id -

guess we forgot to index that

one…that explains the one merge join

& sort!!!

Page 56: er

PlancostPlancost: Post Indexing Join Column: Post Indexing Join Column

==================== Lava Operator Tree ====================

Emit

(VA = 5)

r:32 er:337410

cpu: 300

/

MergeJoin

Inner Join

(VA = 4)

r:32 er:337410

Yehaw! SMJ gone!! Note the

join order changed….

stores � salesdetail � sales

instead of:

sales � stores � salesdetail

56 – © 2011 Sybase, Inc – May 3, 2011

/ \

NestLoopJoin TableScan

Inner Join sales

(VA = 2) (VA = 3)

r:32 er:342041 r:1858 er:132357

l:16 el:1115

p:0 ep:140

/ \

TableScan IndexScan

stores salesdetailind

(VA = 0) (VA = 1)

r:507 er:507 r:32 er:342041

l:12 el:13 l:16397 el:12548

p:0 ep:2 p:0 ep:1379

sales � stores � salesdetail

Yowsa! Note the increase in logical

IO’s …don’t get excited though - this is

due to NLJ….this explains the higher

cpu

Page 57: er

The New ResultsThe New Results

Query 1 NLJ Old SMJ Final

Estimated IO Cost 2,927,215 1,310,046 311,465

Proc cache (opt) 78 86 95

Proc cache hwm (exec) 11 63 15

Private Buffers 0 103 0

Actual IO Cost 1,909,689 66,516 32,850

57 – © 2011 Sybase, Inc – May 3, 2011

Actual IO Cost 1,909,689 66,516 32,850

Total Writes 107 0 0

CPU Time 15,700 100 300

Elapsed Time 22,703 3,906 263

SWEET!!!SWEET!!!

Page 58: er

Think About It for a SecondThink About It for a Second

• Logically:

� The join order stores � sales � salesdetail makes sense

� This would be the natural progression access method master � detail

� And since sales has a clustered index on stor_id, ord_num, the join

stores � sales should use an MJ

• So, let’s force it and see what happens….

58 – © 2011 Sybase, Inc – May 3, 2011

• So, let’s force it and see what happens….

� First we use ‘set option show_abstract_plan on’ to get a full AQP

� Then we just use the parts we want and modify it slightly:select stores.stor_name, stores.city, sales.date,

salesdetail.title_id, salesdetail.qty, salesdetail.discount

from stores, sales, salesdetail

where stores.stor_id = sales.stor_id

and sales.stor_id=salesdetail.stor_id

and sales.ord_num=salesdetail.ord_num

and salesdetail.discount > 50

plan "( m_join

(m_join ( scan stores ) ( scan sales ) )

( scan salesdetail ) )"

Page 59: er

The AQP The AQP �������� PLAN ClausePLAN Clause

• The Actual AQP from show_abstract_plan� ( m_join ( nl_join ( i_scan stor_id_idx stores ) ( i_scan salesdetailind salesdetail ) ) (

i_scan salesind sales ) ) ( prop stores ( parallel 1 ) ( prefetch 32 ) ( lru ) ) ( prop salesdetail ( parallel 1 ) ( prefetch 32 ) ( lru ) ) ( prop sales (parallel 1 ) ( prefetch 32 ) ( lru ) )

• Coming up with our plan

� We only care about the joins…so we can loose the IO & Parallel� ( m_join ( nl_join ( i_scan stor_id_idx stores ) ( i_scan salesdetailind salesdetail ) ) (

i_scan salesind sales ) )

59 – © 2011 Sybase, Inc – May 3, 2011

i_scan salesind sales ) )

� We are using table scan MJ (due to no SARGS) so we can replace i_scan with scan and drop the index names� ( m_join ( nl_join ( scan stores ) ( scan salesdetail ) ) ( scan sales ) )

� Then reorder them stores � sales � salesdetail� ( m_join ( nl_join ( scan stores ) ( scan sales) ) ( scan salesdetail ) )

� …and change the nl_join to m_join� ( m_join ( m_join ( scan stores ) ( scan sales) ) ( scan salesdetail ) )

• Viola!

Page 60: er

PlancostPlancost: Forcing MJ’s Using PLAN Clause: Forcing MJ’s Using PLAN Clause

==================== Lava Operator Tree ====================

Emit

(VA = 5)

r:32 er:337410

cpu: 100

/

MergeJoin

Inner Join

(VA = 4)

r:32 er:337410

l:0 el:7.634e+006

p:0 ep:4118

All MJ’s (table scans) - no SMJ’s

Some stats:

Est IO Cost: 24,653,975!!!!

Proc Cache: 77 & 31 (opt & exec)

Actual IO: 28,764

Elapsed Time: 110ms!!!

Yowsa!!!! Look at the EL!!! This is why the

Estimate IO cost was so high and optimizer

tossed this plan - which is actually the best one.

Estimates from show_lio_costing were:

FINAL PLAN ( total cost = 2.465398e+007 ):

60 – © 2011 Sybase, Inc – May 3, 2011

p:0 ep:4118

/ \

MergeJoin TableScan

Inner Join salesdetail

(VA = 2) (VA = 3)

r:1858 er:101570 r:32 er:445585

l:14365 el:14368

p:0 ep:1796

/ \

TableScan TableScan

stores sales

(VA = 0) (VA = 1)

r:8 er:507 r:1858 er:132357

l:1 el:13 l:16 el:1115

p:0 ep:2 p:0 ep:140

FINAL PLAN ( total cost = 2.465398e+007 ):

lio=7649315 pio=6054.449 cpu=9.203984e+007

Page 61: er

Why the Huge Estimate???Why the Huge Estimate???

• Set statistics io results shows:� Table: stores scan count 1, logical reads: (regular=1 apf=0 total=1), physical reads:

(regular=0 apf=0 total=0), apf IOs used=0

� Table: sales scan count 1, logical reads: (regular=16 apf=0 total=16), physical reads:

(regular=0 apf=0 total=0), apf IOs used=0

� Table: salesdetail scan count 1, logical reads: (regular=14365 apf=0 total=14365),

physical reads: (regular=0 apf=0 total=0), apf IOs used=0

� Total actual I/O cost for this command: 28764.

� Total writes for this command: 0

61 – © 2011 Sybase, Inc – May 3, 2011

� Total writes for this command: 0

• Assume:

� Join stores � sales is outer - estimate is 101570 rows

� We know the final join with MJ table scan is 14365 pages

� Since the scan count is 1 for a table scan MJ, somehow it is estimating

really badly….

• Wait and See

Page 62: er

HmmmmHmmmm……

• In our database, discount is not part of an index

� Therefore no stats….

� Set option show_missing_stats proves this� NO STATS on column salesdetail.discount

• What happens if add column stats - but not an index

� Doesn’t affect the overhead of DML as there is no extra index or index

columns to maintain

62 – © 2011 Sybase, Inc – May 3, 2011

columns to maintain

� With a small number of distinct values, an index might not be all that

useful anyhow….� But the column stats will drop the gross over estimation of 33% to something

realistic

� Is this an argument for sliding scale magic numbers???

� Does affect maintenance in that we occasionally will need to run� update statistics salesdetail (discount)

� If we don’t like the answer, we can drop them…..� delete statistics salesdetail (discount)

Page 63: er

PlancostPlancost: After Adding Column Stats: After Adding Column Stats

==================== Lava Operator Tree ====================

Emit

(VA = 4)

r:32 er:25

cpu: 200

/

NaryNLJoin

(VA = 3)

r:32 er:25

/ \

TableScan NaryNLJoin

stores (VA = 3)

All NaryNLJ’s - no MJ’s

Some stats:

Est IO Cost: 164,351!!!!

Proc Cache: 95 & 11 (opt & exec)

Actual IO: 33,010

Elapsed Time: 286ms

“single” NaryNLJ

“grandparent”

63 – © 2011 Sybase, Inc – May 3, 2011

stores (VA = 3)

(VA = 0) r:32 er:25

r:507 er:507

l:12 el:13

p:0 ep:2

/ \

IndexScan NaryNLJoin

salesdetailind (VA = 3)

(VA = 1) r:32 er:25

r:32 er:25

l:16397 el:12548

p:0 ep:1379

/

IndexScan

salesind

(VA = 2)

r:32 er:25

l:96 el:74

p:0 ep:27

Elapsed Time: 286ms

Interesting - only 32 rows instead

of 33% of 1.3M…maybe an index

is worth it after all???

“parent”

“child”(with SARGS)

Page 64: er

PlancostPlancost: After Adding Index: After Adding Index

==================== Lava Operator Tree ====================

Emit

(VA = 6)

r:32 er:25

cpu: 0

/

NestLoopJoin

Inner Join

(VA = 5)

r:32 er:25

/ \

MergeJoin IndexScan

Inner Join salesind

(VA = 3) (VA = 4)

Some stats:

Est IO Cost: 1,206!!!!

Proc Cache: 93 & 25 (opt & exec)

Actual IO: 222

Elapsed Time: 80ms

Sort is required due to getting

rows into stor_id order for the MJ

Why isn’t this an MJ - theoretically the

left tree is sorted in stor_id order - and

we have a clustered index???

Answer: This is a low cardinality join

(child � parent is 1:1) with a low

estimate << 10% of 1.3M and very high

selectivity - an MJ using a table scan

doesn’t make sense

64 – © 2011 Sybase, Inc – May 3, 2011

(VA = 3) (VA = 4)

r:32 er:25 r:32 er:25

l:96 el:74

p:0 ep:27

/ \

Sort TableScan

(VA = 1) stores

r:32 er:33 (VA = 2)

l:6 el:6 r:8 er:507

p:0 ep:0 l:1 el:13

cpu: 0 bufct: 24 p:0 ep:2

/

IndexScan

discount_idx

(VA = 0)

r:32 er:33

l:14 el:5

p:0 ep:5

rows into stor_id order for the MJ

- but since this is not a table scan

MJ, the sort is less a concern

doesn’t make sense

Page 65: er

The New ResultsThe New Results

Query 1 NLJ Old SMJ Old Final Add Index

Estimated IO Cost 2,927,215 1,310,046 311,465 1,206

Proc cache (opt) 78 86 95 93

Proc cache hwm (exec) 11 63 15 25

Private Buffers 0 103 0 0

Actual IO Cost 1,909,689 66,516 32,850 222

65 – © 2011 Sybase, Inc – May 3, 2011

Actual IO Cost 1,909,689 66,516 32,850 222

Total Writes 107 0 0 0

CPU Time 15,700 100 300 ~0

Elapsed Time 22,703 3,906 263 80

SWEETER YET!!!SWEETER YET!!!

Page 66: er

After Adding Index + Forcing MJ via PLANAfter Adding Index + Forcing MJ via PLAN

==================== Lava Operator Tree ====================

Emit

(VA = 5)

r:32 er:25

cpu: 200

/

MergeJoin

Inner Join

(VA = 4)

r:32 er:25

Some stats:

Est IO Cost: 277,701

Proc Cache: 77 & 31 (opt & exec)

Actual IO: 28,764

Elapsed Time: 110ms

Our gross over estimation

is now fixed as well!!!!

66 – © 2011 Sybase, Inc – May 3, 2011

/ \

MergeJoin TableScan

Inner Join salesdetail

(VA = 2) (VA = 3)

r:1858 er:101570 r:32 er:33

l:14365 el:14368

p:0 ep:1796

/ \

TableScan TableScan

stores sales

(VA = 0) (VA = 1)

r:8 er:507 r:1858 er:132357

l:1 el:13 l:16 el:1115

p:0 ep:2 p:0 ep:140

Why didn’t ASE pick it??

Answer: Cost. Remember the formula cost =

2LIO + 25PIO + 0.1CPU

FINAL PLAN ( total cost = 277701.3 ):

lio=15496 pio=1937 cpu=1982843

Page 67: er

Why That Huge EstimateWhy That Huge Estimate

• New in ASE 15.0:

� Sp_configure…

� cost of a logical io = DEFAULT

� cost of a physical io = DEFAULT

� cost of a cpu unit = DEFAULT

• Cost formula

� Only with defaults� Plan cost = 2*LIO + 25*PIO + 0.1*CPU

67 – © 2011 Sybase, Inc – May 3, 2011

� Plan cost = 2*LIO + 25*PIO + 0.1*CPU

� Actual formula is:� Plan cost = lio_cost * LIO + pio_cost * PIO + (100/cpu_cost) * CPU

� Result it is a bit fun….you have to lower cpu cost to increase plan cost

• Our problem was the 7M LIO’s due to ….???

� Sorts or Join estimates (see next slide)

• So, one way to avoid sorts???

� Set the cost of a cpu unit lower until sort cost is too expensive� Because of the inverse relationship, this will increase cost of sort (e.g. 500 or 250)

� Haven’t tested this in real life yet - so just a possibility

Page 68: er

Remember Me?Remember Me?

==================== Lava Operator Tree ====================

Emit

(VA = 5)

r:32 er:337410

cpu: 100

/

MergeJoin

Inner Join

(VA = 4)

r:32 er:337410

l:0 el:7.634e+006

p:0 ep:4118

Focus on the er….why were the join estimates so high???

Well, since we don’t have stats on discount and no other SARGS exist,

we have to assume a 1-to-many join for each of the join.

The formula for estimating rows is

Outer rows * inner rows * join column scan selectivity (inner rows) for

index used on the join

So for the first join (stores����sales) we would have 507 * 132357 *

68 – © 2011 Sybase, Inc – May 3, 2011

p:0 ep:4118

/ \

MergeJoin TableScan

Inner Join salesdetail

(VA = 2) (VA = 3)

r:1858 er:101570 r:32 er:445585

l:14365 el:14368

p:0 ep:1796

/ \

TableScan TableScan

stores sales

(VA = 0) (VA = 1)

r:8 er:507 r:1858 er:132357

l:1 el:13 l:16 el:1115

p:0 ep:2 p:0 ep:140

So for the first join (stores����sales) we would have 507 * 132357 *

selectivity of stor_id in sales table….which for a table scan is either

indid of 1 or 0 ….set option show on reveals:

Estimating selectivity of index 'sales.salesind', indid 1

stor_id = stor_id

Estimated selectivity for stor_id,

selectivity = 0.001513594,

scan selectivity 0.001513594, filter selectivity 0.001513594

...so we have 507 * 132357 * 0.001513594 = 101569.72

…which of course is rounded up to 101,570 rows….

…now for the next join

Page 69: er

Remember Me? (cont)Remember Me? (cont)

==================== Lava Operator Tree ====================

Emit

(VA = 5)

r:32 er:337410

cpu: 100

/

MergeJoin

Inner Join

(VA = 4)

r:32 er:337410

l:0 el:7.634e+006

p:0 ep:4118

…that’s (previous page) the outer table in the join to ����

salesdetail….which we had 1.3M rows at 33% for 445585

rows…checking the …set option show on output….

Estimating selectivity of index 'salesdetail.salesdetailind', indid 1

stor_id = stor_id, stor_id

ord_num = ord_num

Estimated selectivity for stor_id,

selectivity = 0.001948715,

Estimated selectivity for ord_num,

selectivity = 7.505242e-006,

69 – © 2011 Sybase, Inc – May 3, 2011

p:0 ep:4118

/ \

MergeJoin TableScan

Inner Join salesdetail

(VA = 2) (VA = 3)

r:1858 er:101570 r:32 er:445585

l:14365 el:14368

p:0 ep:1796

/ \

TableScan TableScan

stores sales

(VA = 0) (VA = 1)

r:8 er:507 r:1858 er:132357

l:1 el:13 l:16 el:1115

p:0 ep:2 p:0 ep:140

selectivity = 7.505242e-006,

Clustered Index Data Row Filtering Predicates

discount > 50

Estimated selectivity for discount,

selectivity = 0.33,

scan selectivity 7.505169e-006, filter selectivity 2.476706e-006

Again, a bit of math 101570 outer rows * 445585 inner rows *

7.505169e-006 = 339669.45…likely something else considered but you

can see how we are in the same ballpark….

….so wildly huge join estimates way above actual rows points to poorly

indexed join.

Page 70: er

Controlling Merge JoinsControlling Merge Joins

• Step 1: Eliminate the “sorts” on table scan SMJ

� Sorting involves quite a bit of cpu time - and memory

� Reducing sorts can dramatically increase response times as well as improve system concurrency as more cpu available for others

� Be careful - not all MJ’s use table scan - if inner table is using a different SARG index, the sort may be necessary as the SARG index is helpful

• Make sure join keys all have stats

� No missing stats on join keys

• Make a SMJ into a plain MJ

70 – © 2011 Sybase, Inc – May 3, 2011

• Make a SMJ into a plain MJ

� Tip: create a clustered index with the join keys as leading columns

• Make a SMJ ���� NLJ

� Make sure the join is indexed

� Typically more of an issue for #temps - which only get used once� ...but if used more than once consider an index on #temp

• Step 2: Reduce the row estimates

� Consider stats or an index on low cardinality column� Use stats first to see if estimated rows is worth it

� Debate the tradeoff of extra index overhead for DML vs. query perf

Page 71: er

What If This Doesn’t Help???What If This Doesn’t Help???

• Try changing the OptGoal

� This varies which subsets of optimization criteria are used

� Some optgoals are specific to particular CR’s

• Try different opt criteria

� Look for opt criteria in the showplan or plancost that involve sorting

or other high resource usage

71 – © 2011 Sybase, Inc – May 3, 2011

or other high resource usage

� In an index didn’t resolve the sort - optimizer may not be allowing it

for some other reason

� See what optcriteria is currently in use

� Try the query with a different criteria� E.g. hash_union_distinct vs. merge_union_distinct

Page 72: er

OptgoalsOptgoals & Join & Join Methods/FeaturesMethods/Features

NL

J

SM

J

HJ

N-a

ry N

LJ

Pro

xy T

ab

le/C

IS

Para

llel Q

uery

Sta

r Sch

em

a

Bu

sh

y J

oin

Eag

er A

gg

reg

atio

n

72 – © 2011 Sybase, Inc – May 3, 2011

Eag

er A

gg

reg

atio

n

allrows_oltp ���� * ����

allrows_mix (default) ���� ���� ���� ���� ���� ����

allrows_dss ���� ���� ���� ���� ���� ���� ���� ���� ����

* May still use merge join in some cases according to ASE PSE

Page 73: er

master..sysoptionsmaster..sysoptions

73 – © 2011 Sybase, Inc – May 3, 2011

Page 74: er

Which OptCriteria To TryWhich OptCriteria To Try

• Joins� nl_join, nary_nl_join,

merge_join, hash_join

� bushy_space_search,

alternative_greedy_search

• Union� merge_union_distinct,

hash_union_distinct

• Index/Reformatting� multi_table_store_ind

� store_index

• Index Selection/Order By� mnc_full_index_filter

� streaming_sort, order_sorting

� index_union, index_intersection

• Group By/Aggregates

74 – © 2011 Sybase, Inc – May 3, 2011

hash_union_distinct

• Union All� append_union_all,

merge_union_all

• Distinct� no_stats_distinctness

� opportunistic_distinct_view

� distinct_sorting, distinct_sorted,

distinct_hashing

• Group By/Aggregates� group_sorted, group_inserting,

group_hashing

� advanced_aggregation

Page 75: er

Deploying Query Tuning Fixes

75 – Sybase Confidential – May 3, 2011

Page 76: er

Tools for Deploying Query Fixes Tools for Deploying Query Fixes

• Query Rewrite

� Best option for bad SQL/SQL tuned for 12.5 optimizer

� Best solution for stored procedures

• Stored Procedure optgoals/controls

� Good solution for stored procs with a large number of queries with similar issues

• Query PLAN Clause

76 – © 2011 Sybase, Inc – May 3, 2011

• Query PLAN Clause

� Good for isolating a fix to a specific query - especially when the SARG’s vary widely from one invocation to the next

• Abstract Query Plans

� Good for fixing a common query with consistent SARG criteria

• Login Trigger

� Best way to enable optimization features/controls based on application generic requirements

Page 77: er

Login TriggerLogin Trigger

• Your BEST friend in a migration (other than testing)

• Allows you to control and set “optimization profiles”

� …for OLTP vs. reporting apps

� …for batch programs

� …for electronic feeds

• Allows you to gradually introduce ASE 15 optimization to a

77 – © 2011 Sybase, Inc – May 3, 2011

• Allows you to gradually introduce ASE 15 optimization to a

less than thoroughly tested application

� Start with compatibility mode or allrows_oltp

� Turn off compatibility mode or increase optgoal� Application by application, or…

� …appserver by appserver (25%, 50%, 75%, 100% of user population)

� …IP address ranges for clients

� …login name

� …mod of the SPID (if nothing else)

� …anything visible in master..sysprocesses

Page 78: er

Example Optimization Profile ScenariosExample Optimization Profile Scenarios

• Replication Server

� Login trigger detects replication_role� Enables statement cache + literal parameterization

� Sets optgoal allrows_oltp

� Sets delayed commit on

� Dynamic listeners allow RS to connect while blocking other users� E.g. warm standby

• Batch Load Program

78 – © 2011 Sybase, Inc – May 3, 2011

• Batch Load Program

� Login trigger sets delayed commit on

• Report Daemon

� Login trigger detects application name or login name� Disables statement cache

� Sets optgoal allrows_dss

� Increases optimization timeout limit

� Enables qp metrics for long running queries

� Application/login binding to separate tempdb (DSS optimized devices)

Page 79: er

Sample Login Trigger (1)Sample Login Trigger (1)

-- created in master to allow prevent login failures in case the server needs to

-- be booted with traceflag to recover master database only

use master

go

create table optimization_profile (

appname varchar(30) not null,

opt_goal varchar(20) not null,

parallel_deg tinyint not null,

use_stmtcache bit not null,

use_mergejoin bit not null,

use_hashjoin bit not null,

79 – © 2011 Sybase, Inc – May 3, 2011

use_hashjoin bit not null,

use_idxunion bit not null,

compatibility_mode bit not null,

delayed_commit bit not null,

-- other attributes/opt criteria as desired/necessary

primary key (appname)

)

go

exec sp_logintrigger 'drop'

go

if exists (select 1 from sysobjects where name='sp_optimization_profile’ and type='P' and

uid=user_id())

drop procedure sp_optimization_profile

go

print "...creating procedure: 'sp_optimization_profile'"

go

Page 80: er

Sample Login Trigger (2)Sample Login Trigger (2)

create procedure sp_optimization_profile

as begin

declare @appname varchar(30),

@opt_goal varchar(20),

@use_stmtcache bit,

@use_mergejoin bit,

@use_hashjoin bit,

@use_idxunion bit,

@compatibility_mode bit,

@delayed_commit bit

if suser_name()='sa' return 0

80 – © 2011 Sybase, Inc – May 3, 2011

if suser_name()='sa' return 0

if has_role('sa_role',0)=1 return 0

select @appname=(case when clientapplname is not null

then clientapplname

else program_name end)

from master..sysprocesses

where spid=@@spid

--because login trigger, all future ‘set’ clauses are automatically exported

if exists (select appname from master..optimization_profile

where appname=@appname)

begin

select @opt_goal=opt_goal,

@use_stmtcache=use_stmtcache, … -- <list of criteria>

from master..optimization_profile

where appname=@appname

Page 81: er

Sample Login Trigger (3)Sample Login Trigger (3)

if @opt_goal="allrows_oltp" set plan optgoal allrows_oltp

if @opt_goal="allrows_mix" set plan optgoal allrows_mix

if @opt_goal="allrows_dss" set plan optgoal allrows_dss

if @use_stmtcache=1

begin

set statement_cache on

set literal_autoparam on

end

else

begin

81 – © 2011 Sybase, Inc – May 3, 2011

begin

set statement_cache off

end

if @delayed_commit=1 set delayed_commit on

end

return 0

end

go

grant exec on sp_optimization_profile to public

go

exec sp_logintrigger 'master..sp_optimization_profile'

go

Page 82: er