SQL_Query_Tracing_fo..

advertisement
SQL Query Tracing for RQM Developers
Overview
How you trace into SQL depends on what you are trying to discover.
If you would like to see all the SQL associated with a single RQM service call, the best option is
using log4j. With that, you can filter the output for a single service call made from the web UI.
If you are looking at all the SQL associated with a scenario, repodebug can be very useful. Once
you have a collection of SQL statements, you can focus on the ones that are most expensive (or
repeated a lot) from your scenario. You can then turn on stack tracing, and determine where the
SQL statement was called in your RQM code.
If you have RQM code that makes query and you want to find out what the SQL that is generated
is, you can put a breakpoint and see the specific value.
Using log4j
Turning this on will cause the console output from your RQM repository to spew massive
amounts of information. I find the best trick is to enable it, then quickly run the scenario, and
then turn it off again. There are 2 different ways to turn it on dynamically while the server is
running.
Enable log4j using jazz/admin
If you go to the URL http://host:port/jazz/admin?internal=true you will find under “Reload Log
Settings” under “Internal Tools” towards the bottom of the left hand side. If you click on “Reload
Log Settings” you will see a single button “Reload Log Settings”. Pressing this will cause the
server to re-load the log4j.properties file.
In the log4j.properties file, you should add these lines if they do not already exist:
# Turn on debugging of all SQL
log4j.logger.sqlTxLogger=DEBUG
Save the file, clear the console window, and then push the “Reload Log Settings” button. Massive
amounts of output will begin immediately. You should probably turn off the limit on the console
size before you do this, or some of the output could be lost. You can do this by using the mouse
to right-click in the console window, and then from the preferences section disable the “Limit
console output” checkbox.
I recommend that you have your web UI scenario queued up before you push the button. What I
actually do is change the setting to DEBUG and save the file, and then in the editor I change the
setting back to ERROR but do not save.
log4j.logger.sqlTxLogger=ERROR
Then I press the button, run my scenario quickly, hit save in the log4j.properties editor window,
and then hit the button one last time. After this, I copy and save the full SQL trace for editing and
analysis.
Enable log4j tracing using repodebug
If you go to the URL such as
http://host:port/jazz/repodebug
then click on
log->loggers
at the bottom you see the sqlTxLogger. Click on that, and you see the current setting for that
logger (presumably ERROR). Click on “editLevel”, and you can change the level to DEBUG. Again,
once you hit the Submit button, the logging will start, so again, be quick about running your
scenario and resetting the logger to ERROR.
Analyzing the SQL trace output
Several of the asynchronous tasks use a lot of SQL, which is why your output will have extra SQL
that is not explicitly from your scenario.
I typically will trim the trace output using something like:
grep "sql =>" trace.txt >sql.txt
Then, I edit the sql.txt file and look for the specific scenario, skipping over the asynchronous task
output. For example, a line of trace output for a “browse test case scenario” might look like:
17:26:14,588 [1071268113@qtp-1954570098-49 @@ 17:26 TestJazzAdmin1
<com.ibm.rqm.planning.home.actionDispatcher/viewTestCases@2b4ee1cc-35dc-475e-887204ed3bcdb39f>
/jazz/service/com.ibm.rqm.web.common.service.rest.ICompositeWebRestService/browseInitDa
ta] DEBUG sqlTxLogger
- ConnectionStatWrapper(type 4, 22737, dirty: true,
b(15919491)) sql => select t1.ITEM_ID, t1.STATE_ID from PLANNING.CUSTOM_ATTRIBUTE t1
where ((t1.PROJECT_AREA_ITEM_ID = ?) and (t1.SCOPE_COL = ?) and (t1.ARCHIVED = 0)) order
by t1.NAME_COL asc
You can see lots of interesting information, such as when the trace occurred, and what user
(TestJazzAdmin1) performed the action. After that, you see the marker that tells you the
scenario (viewTestCases) and a unique id such as
2b4ee1cc-35dc-475e-8872-04ed3bcdb39f
You can then use filter using that to get just the lines associated with the scenario
grep "2b4ee1cc-35dc-475e-8872-04ed3bcdb39f" sql.txt >browseTestCase.txt
You can also see the specific service call used by the web UI in each trace output line. In the
example above, see: ICompositeWebRestService/browseInitData
Sometimes I am looking at the entire scenario, other times I am looking at a single service call.
Once I decide, I will often trim the output one last time by stripping out the text using a regular
expression like:
.*sql =>
That gives me a more compact sequence of output, where I can focus on the SQL alone.
Using repodebug
You can get SQL tracing directly from repodebug. Again, go to a URL such as
http://host:port/jazz/repodebug
This time, go into
database->queryStats
Here you can start and stop SQL tracing. So let’s look at the same scenario, “browse test cases”.
Start the SQL tracing by clicking “start” and then again quickly run the scenario, return to the
repodebug page and click on stop.
This produces a somewhat nicely formatted table of output divided into sections for write, read,
and other. SQL statements are sorted by total time, and if the count of the number of times each
statement occurred is listed. In our scenario of “browse test cases” there are 10 rows displayed,
and we can see that certain SQL statements are run 10 times. This is a hint that such statements
occur once per row.
Unfortunately, many of our SQL statements are long, and this makes looking at the entire table a
bit tricky. You can scroll the table to the right, and eventually you will see other columns listing
performance statistics, as well as whether stack tracing is enabled for this statement.
Unfortunately the actual sequence of the tracing is gone, so the SQL from asynchronous tasks
may be intermixed. Some of these are easy to spot, such as:
SELECT T1.ITEM_ID, T1.STATE_ID FROM PRINT.PRINT_JOB…
SELECT T1.ITEM_ID, T1.STATE_ID FROM LM.RUNNING_JOB…
SELECT T1.ITEM_ID, T1.STATE_ID FROM LM.RUNNING_DISCOVERY…
Finding the stack traces for your SQL
There is a column in the output labeled “hash” and each entry is a clickable link. If you click on
such a hash value in a row, it takes you to information about that SQL statement. It also provides
an action at the top for “enableStacks”. Once you click that, stack tracing is on for this specific
SQL statement. You can then start tracing again, run your scenario, and stop tracing. Then, when
you click on the hash link for your statement, you will see that the output contains one or more
stacktraces where the SQL occurred.
Using the debugger
You can use the debugger to find the actual SQL being generated for a specific query. Setting a
breakpoint in the repository code generally does not work well, as the asynchronous tasks will
hit it pretty quickly. If you are OK with stopping the tasks, you can simply let the breakpoints
occur and not resume execution for the asynchronous tasks.
More commonly, if you know the RQM code where you want to find the SQL, you can set a
breakpoint in the RQM code. Then you can go to the code for
com.ibm.team.repository.service.internal.ExecuteDataQuery.doServerQueryData()
and look around line 92 where you will see
String trueSQL = aResult.query();
Once your breakpoint hits in RQM code, you can use the debugger option “Run To Line” to run
until the line 93 (after the trueSQL has been calculated). This will not set a full breakpoint, and
only your thread will stop at that line. For the trueSQL variable you may see something like:
select t1.ITEM_ID, t1.STATE_ID, t1.JZ_DISCRIMINATOR from (select * from
PLANNING.VERSIONABLE_ITEM z1 where z1.JZ_DISCRIMINATOR = 151) t1 left outer
join PLANNING.VERSIONED_TEST_PLAN_TEST_CASES j1 on
(t1.VERSIONED_TEST_PLAN_TEST_CASES = j1.JZ_PARENT_ID) left outer join
PLANNING.VERSIONABLE_ITEM t2 on (j1.ITEM_ID = t2.ITEM_ID) where
((t2.ITEM_ID = ?) and (t1.ARCHIVED = 0))
And if you are interested in the predicate used in the query, you can look at the variable
query.filter
where you can see something like
r.testCases().itemId()._eq(q.newUUIDArg())._and(r.archived()._eq(0))
(operator: AND)
Download