If this is your first visit, be sure to check out the FAQ by clicking the link above. You may have to register before you can post: click the register link above to proceed. To start viewing messages, select the forum that you want to visit from the selection below.

 
Go Back  dBforums > Database Server Software > DB2 > Large Query - Is UNION ALL the best option?

Reply
 
LinkBack Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old 05-20-09, 16:23
DBFinder DBFinder is offline
Registered User
 
Join Date: Sep 2008
Location: Toronto,Canada
Posts: 606
Large Query - Is UNION ALL the best option?

Hello,

Can some one help me decide if the query can use some other thing to improve perf.

Code:
SELECT total_bets, credited_bets, total_payouts, game_type, game_code
FROM 
(
SELECT SUM(total_bets) AS total_bets, SUM(credited_bets) AS credited_bets, SUM(total_payouts) AS total_payouts, game_type AS game_type, game_code AS game_code, casino_id AS casino_id
FROM 
(
	SELECT SUM(bets) AS total_bets, SUM(bets * (COALESCE(percentage, 0)/100.0)) AS credited_bets, SUM(payouts) AS total_payouts, cg.display_type AS game_type, cg.component_id AS game_code, SUBSTR(acc_num, 1, 2) AS casino_id
	FROM player_stats p INNER JOIN component_group cg ON cg.group_id = p.group_id
	LEFT OUTER JOIN component_group_wager w ON p.group_id = w.group_id AND SUBSTR(acc_num, 1, 2) = w.merchant 
	WHERE  acc_num = 'TT0845162881' AND DATE(TIMESTAMP) >= DATE('1999-01-01-00.00.00') AND DATE(TIMESTAMP) < DATE(CURRENT TIMESTAMP - 1 DAY)
	GROUP BY cg.display_type, cg.component_id, acc_num
UNION ALL
	SELECT SUM(bet_amt) AS total_bets, SUM(bet_amt * (COALESCE(percentage, 0)/100.0)) AS credited_bets, SUM(win_amt) AS total_payouts, cg.display_type AS game_type, pgs.component_id AS game_code, SUBSTR(acc_num, 1, 2) AS casino_id
	FROM player_g_session pgs INNER JOIN component_group cg ON cg.group_id = pgs.group_id
	LEFT OUTER JOIN component_group_wager w ON pgs.group_id = w.group_id AND SUBSTR(acc_num, 1, 2) = w.merchant 
	WHERE  acc_num = 'TT0845162881' AND timestamp >= 
	(SELECT CASE WHEN TIMESTAMP('1999-01-01-00.00.00') > TIMESTAMP(CURRENT DATE - 1 DAY, '00.00.00') THEN TIMESTAMP('1999-01-01-00.00.00') ELSE TIMESTAMP(CURRENT DATE - 1 DAY, '00.00.00') END FROM CLIENT_ACC FETCH FIRST 1 ROW ONLY)
	AND timestamp < TIMESTAMP(DATE(CURRENT TIMESTAMP - 1 HOUR), RTRIM(CHAR(HOUR(CURRENT TIMESTAMP -1 HOUR))) || '.00.00')
	GROUP BY cg.display_type, pgs.component_id, acc_num
UNION ALL
	SELECT SUM(bet_amt) AS total_bets, SUM(bet_amt * (COALESCE(percentage, 0)/100.0)) AS credited_bets, SUM(win_amt) AS total_payouts, cg.display_type AS game_type, cg.component_id AS game_code, SUBSTR(acc_num, 1, 2) AS casino_id
	FROM game_trans g INNER JOIN blackjack_d b ON g.game_trans_id = b.game_trans_id 
	LEFT OUTER JOIN component_group cg ON cg.group_id = g.group_id
	LEFT OUTER JOIN component_group_wager w ON b.group_id = w.group_id AND SUBSTR(acc_num, 1, 2) = w.merchant 
	WHERE mode = 'R' AND player = 9 AND (b.ended = 'TRUE' OR b.ended IS NULL ) AND acc_num = 'TT0845162881' AND timestamp >= 
	(SELECT CASE WHEN TIMESTAMP('1999-01-01-00.00.00') > TIMESTAMP(DATE(CURRENT TIMESTAMP - 1 HOUR), RTRIM(CHAR(HOUR(TIME(CURRENT TIMESTAMP -1 HOUR)))) || '.00.00') THEN TIMESTAMP('1999-01-01-00.00.00') ELSE TIMESTAMP(DATE(CURRENT TIMESTAMP - 1 HOUR), RTRIM(CHAR(HOUR(TIME(CURRENT TIMESTAMP -1 HOUR)))) || '.00.00') END FROM CLIENT_ACC FETCH FIRST 1 ROW ONLY)
	GROUP BY cg.display_type, cg.component_id, acc_num
UNION ALL
	SELECT SUM(bet_amt) as total_bets, SUM(bet_amt * (COALESCE(percentage, 0)/100.0)) AS credited_bets, SUM(win_amt) AS total_payouts, cg.display_type AS game_type, cg.component_id AS game_code, SUBSTR(acc_num, 1, 2) AS casino_id
	FROM game_trans g INNER JOIN fivereel_d f ON g.game_trans_id = f.game_trans_id 
	LEFT OUTER JOIN component_group cg ON cg.group_id = g.group_id
	LEFT OUTER JOIN component_group_wager w ON f.group_id = w.group_id AND SUBSTR(acc_num, 1, 2) = w.merchant 
	WHERE mode = 'R' AND acc_num = 'TT0845162881' AND timestamp >= 
	(SELECT CASE WHEN TIMESTAMP('1999-01-01-00.00.00') > TIMESTAMP(DATE(CURRENT TIMESTAMP - 1 HOUR), RTRIM(CHAR(HOUR(TIME(CURRENT TIMESTAMP -1 HOUR)))) || '.00.00') THEN TIMESTAMP('1999-01-01-00.00.00') ELSE TIMESTAMP(DATE(CURRENT TIMESTAMP - 1 HOUR), RTRIM(CHAR(HOUR(TIME(CURRENT TIMESTAMP -1 HOUR)))) || '.00.00') END FROM CLIENT_ACC FETCH FIRST 1 ROW ONLY)
	GROUP BY cg.display_type, cg.component_id, acc_num
UNION ALL
:
:
:
And this one has 22 sections UNIONed ALL together.

This is reported to be slow.

Thanks

DBFinder
Attached Files
File Type: txt large_query.txt (20.3 KB, 46 views)
Reply With Quote
  #2 (permalink)  
Old 05-20-09, 20:03
n_i n_i is offline
:-)
 
Join Date: Jun 2003
Location: Toronto, Canada
Posts: 4,449
It may benefit from an MQT. Try running it through db2advis.
Reply With Quote
  #3 (permalink)  
Old 05-21-09, 06:32
Peter.Vanroose Peter.Vanroose is offline
Registered User
 
Join Date: Sep 2004
Location: Belgium
Posts: 1,079
The "UNION ALL"s all probably fine.
I'd rather go for eliminating all non-sargable (i.e., stage-2) predicates.
For example, "DATE(TIMESTAMP) >= DATE('1999-01-01-00.00.00')" is equivalent to "TIMESTAMP >= TIMESTAMP('1999-01-01-00.00.00')".

It also seems to me that the subquery
Code:
(SELECT CASE
  WHEN TIMESTAMP('1999-01-01-00.00.00')>TIMESTAMP(CURRENT DATE-1 DAY,'00.00.00')
  THEN TIMESTAMP('1999-01-01-00.00.00')
  ELSE TIMESTAMP(CURRENT DATE - 1 DAY, '00.00.00')
 END FROM CLIENT_ACC FETCH FIRST 1 ROW ONLY)
can safely be replaced by
Code:
TIMESTAMP(CURRENT DATE - 1 DAY, '00.00.00')
or otherwise at least remove the dependency on table CLIENT_ACC which need not be accessed, i.e. replace the whole subquery by just the CASE expression.
Or even better: replace the predicate "timestamp >= CASE ... END" by the two predicates
Code:
timestamp >= TIMESTAMP(CURRENT DATE - 1 DAY, '00.00.00')
AND
timestamp >= TIMESTAMP('1999-01-01-00.00.00')
You may also safely replace "SUM(bet_amt * (COALESCE(percentage, 0)/100.0))" by "SUM(0.01*bet_amt*percentage)".
And if there really is always a fixed "AND acc_num = 'TT0845162881'" in all parts (but that's probably just one test case, I presume), you should replace all occurrences of "SUBSTR(acc_num, 1, 2)" by 'TT'.

There are most likely some other optimisations which will improve the preformance drastically, but those require knowledge of the table design and the data statistics.
__________________
--_Peter Vanroose,
__IBM Certified Database Administrator, DB2 9 for z/OS
__IBM Certified Application Developer
__ABIS Training and Consulting
__http://www.abis.be/

Last edited by Peter.Vanroose; 05-21-09 at 06:43.
Reply With Quote
  #4 (permalink)  
Old 05-21-09, 07:45
dr_te_z dr_te_z is offline
Registered User
 
Join Date: Jan 2009
Location: Zoetermeer, Holland
Posts: 555
MQT: good advice. You can try the CTE approach like this:
Code:
with cte_temp as 
   ( 
	SELECT bets
             , percentage
             , payouts
             , mode
             , player
             , cg.display_type 
             , cg.component_id 
             , acc_num
  	           FROM player_stats          p 
        INNER      JOIN component_group      cg ON cg.group_id = p.group_id
	LEFT OUTER JOIN component_group_wager w ON  p.group_id = w.group_id 
                                               AND SUBSTR(acc_num, 1, 2) = w.merchant 
        WHERE  acc_num = 'TT0845162881'
   ) 

SELECT total_bets, credited_bets, total_payouts, game_type, game_code
FROM 
(
SELECT SUM(total_bets) AS total_bets, SUM(credited_bets) AS credited_bets, SUM(total_payouts) AS total_payouts, game_type AS game_type, game_code AS game_code, casino_id AS casino_id
FROM 
(
	SELECT SUM(bet_amt) as total_bets
             , SUM(bet_amt * (COALESCE(percentage, 0)/100.0)) AS credited_bets
             , SUM(win_amt) AS total_payouts
             , display_type AS game_type
             , component_id AS game_code
             , SUBSTR(acc_num, 1, 2) AS casino_id

	FROM cte_temp  

	WHERE mode = 'R' 
          AND timestamp >= (
                              SELECT CASE WHEN TIMESTAMP('1999-01-01-00.00.00') > TIMESTAMP(DATE(CURRENT TIMESTAMP - 1 HOUR)
                            , RTRIM(CHAR(HOUR(TIME(CURRENT TIMESTAMP -1 HOUR)))) || '.00.00') 
                              THEN TIMESTAMP('1999-01-01-00.00.00') 
                              ELSE TIMESTAMP(DATE(CURRENT TIMESTAMP - 1 HOUR)
                            , RTRIM(CHAR(HOUR(TIME(CURRENT TIMESTAMP -1 HOUR)))) || '.00.00') END 
                              FROM CLIENT_ACC FETCH FIRST 1 ROW ONLY
                           )
	GROUP BY cg.display_type, cg.component_id, acc_num
UNION ALL 	SELECT ...  
         	FROM cte_temp
	        WHERE ... 
UNION ALL 	SELECT ...  
         	FROM cte_temp
	        WHERE ... 
UNION ALL 	SELECT ...  
         	FROM cte_temp
	        WHERE ...
... 
e_type, wagers.game_code, wagers.casino_id
) sum_wagers
ORDER BY TOTAL_BETS
Selection & joining only done once. Maybe faster, more easy SQL-source maintenance.

Last edited by dr_te_z; 05-21-09 at 08:06.
Reply With Quote
  #5 (permalink)  
Old 05-21-09, 11:20
DBFinder DBFinder is offline
Registered User
 
Join Date: Sep 2008
Location: Toronto,Canada
Posts: 606
Thanks, peter and dr_te_z


I will try few examples on MQT and advise the dev guys shortly.


DBFinder
Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On