SlideShare a Scribd company logo
PL/pgSQL
Debugging
Who Am I?
● Jim Mlodgenski
– jimm@openscg.com
– @jim_mlodgenski
● Director
– United States PostgreSQL (www.postgresql.us)
● Co-organizer of
– Philly PUG (www.phlpug.org)
– NYC PUG (www.nycpug.org)
● CTO, OpenSCG
– www.openscg.com
Debugging Your PL/pgSQL Code
Fantasy Football
● Fantasy football is a
statistical game in
which players compete
against each other by
managing groups of
real players or position
units selected from
American football
teams.
Debugging Your PL/pgSQL Code
Debugging Your PL/pgSQL Code
Debugging Your PL/pgSQL Code
Business Rules
● Passing
– Touchdown (4 points)
– Every 25 yards (1 point)
– Interception (-1 point)
● Rushing
– Touchdown (6 points)
– Every 10 yards (1 point)
● Receiving
– Touchdown (6 points)
– Every 10 yards (1 point)
Sample Schema
Choosing a Language
Procedures
CREATE OR REPLACE FUNCTION rushing_score(p_player_key VARCHAR,
p_year int,
p_week int)
RETURNS INT AS
$$
DECLARE
score INT;
BEGIN
-- 1 point for every 10 yards rushing
SELECT r.yards/10
INTO score
FROM rushing r, games g
WHERE r.game_id = g.game_id
AND g.year = p_year
AND g.week = p_week
AND r.player_key = p_player_key;
IF score IS NULL THEN
RETURN 0;
END IF;
RETURN score;
END;
$$ LANGUAGE plpgsql;
Procedures
CREATE OR REPLACE FUNCTION player_game_score(p_player_key VARCHAR, p_year int, p_week int)
...
BEGIN
score := 0;
-- Get the position of the player
SELECT position
INTO l_position
FROM player
WHERE player_key = p_player_key;
IF l_position = 'qb' THEN
score := score + passing_score(p_player_key, p_year, p_week);
score := score + rushing_score(p_player_key, p_year, p_week);
score := score + td_score(p_player_key, p_year, p_week);
ELSIF l_position = 'rb' THEN
score := score + rushing_score(p_player_key, p_year, p_week);
score := score + td_score(p_player_key, p_year, p_week);
ELSIF l_position = 'wr' THEN
score := score + receiving_score(p_player_key, p_year, p_week);
score := score + td_score(p_player_key, p_year, p_week);
ELSIF l_position = 'te' THEN
score := score + receiving_score(p_player_key, p_year, p_week);
score := score + td_score(p_player_key, p_year, p_week);
ELSE
return 0;
END IF;
return score;
END;
$$ LANGUAGE plpgsql;
Procedures
CREATE OR REPLACE FUNCTION avg_yearly_score(p_player_key
VARCHAR,
p_year int)
RETURNS REAL AS
$$
DECLARE
score INT;
i INT;
BEGIN
score := 0;
FOR i IN 1..17 LOOP
score := score + player_game_score(p_player_key,
p_year, i);
END LOOP;
RETURN score/16.0;
END;
$$ LANGUAGE plpgsql;
Debugging: RAISE
CREATE OR REPLACE FUNCTION passing_score(p_player_key VARCHAR, p_year int, p_week
int)
RETURNS INT AS
$$
...
BEGIN
score := 0;
-- 1 point for every 25 yards passing
SELECT p.pass_yards/25
INTO yardage_score
FROM passing p, games g
WHERE p.game_id = g.game_id
AND g.year = p_year
AND g.week = p_week
AND p.player_key = p_player_key;
IF yardage_score IS NULL THEN
yardage_score := 0;
END IF;
RAISE NOTICE 'Passing Yards Score: %', yardage_score;
Debugging: RAISE
nfl=# select passing_score('BreeDr00',
2005, 5);
NOTICE: Passing Yards Score: 8
NOTICE: Passing TD Score: 4
NOTICE: Interception Score: -2
passing_score
---------------
10
(1 row)
Debugger
git://git.postgresql.org/git/pldebugger.git
make USE_PGXS=1
make install USE_PGXS=1
- OR -
http://community.openscg.com/se/postgresql/packages.jsp
shared_preload_libraries =
'$libdir/plugin_debugger'
CREATE EXTENSION pldbgapi;
Demo
Debugger
Debugger
Debugger
Debugging Triggers
Debugging Triggers
Debugging: RAISE
nfl=# SELECT p.first_name, p.last_name,
p.position,
avg_yearly_score(p.player_key, 2006) AS score
FROM player p
WHERE p.player_key IN (SELECT *
FROM yearly_player(2005))
AND avg_yearly_score(p.player_key, 2006) > 10
ORDER BY 4 DESC;
Debugging: RAISE
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Passing TD Score: 8
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Interception Score: -2
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Passing Yards Score: 9
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Passing TD Score: 4
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Interception Score: 0
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Passing Yards Score: 10
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Passing TD Score: 8
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Interception Score: -4
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Passing Yards Score: 7
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Passing TD Score: 4
CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment
PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment
NOTICE: Interception Score: -2
...
Track Functions
set track_functions = 'PL';
nfl=# SELECT * FROM pg_stat_user_functions;
funcid | schemaname | funcname | calls | total_time | self_time
--------+------------+-------------------+-------+------------+-----------
20564 | public | avg_yearly_score | 547 | 7011.25 | 13.33
20565 | public | passing_score | 1666 | 1551.862 | 1551.862
20566 | public | player_game_score | 9299 | 6997.92 | 188.718
20567 | public | receiving_score | 4811 | 2465.982 | 2465.982
20568 | public | rushing_score | 4488 | 2303.934 | 2303.934
20569 | public | td_score | 9299 | 487.424 | 487.424
20570 | public | yearly_player | 1 | 14.139 | 14.139
(7 rows)
Profiler
https://bitbucket.org/openscg/plprofiler.git
make USE_PGXS=1
make install USE_PGXS=1
- OR -
http://community.openscg.com/se/postgresql/packages.jsp
shared_preload_libraries =
'$libdir/plprofiler.so'
CREATE EXTENSION plprofiler;
Demo
Profiler
nfl=# SELECT * FROM pl_profiler;
ERROR: plprofiler must be loaded and enabled
STATEMENT: SELECT * FROM pl_profiler;
nfl=# SELECT pl_profiler_enable(true);
pl_profiler_enable
--------------------
t
(1 row)
Profiler
nfl=# SELECT p.first_name, p.last_name, p.position,
nfl-# avg_yearly_score(p.player_key, 2006) AS score
nfl-# FROM player p
nfl-# WHERE p.player_key IN (SELECT * FROM
yearly_player(2005))
nfl-# AND avg_yearly_score(p.player_key, 2006) > 10
nfl-# ORDER BY 4 DESC;
first_name | last_name | position | score
------------+----------------+----------+---------
LaDainian | Tomlinson | rb | 22.5
Peyton | Manning | qb | 18.875
Larry | Johnson | rb | 17.875
Michael | Vick | qb | 15.875
Drew | Brees | qb | 15.75
Marc | Bulger | qb | 15.5625
Steven | Jackson | rb | 15.1875
Carson | Palmer | qb | 15.125
Willie | Parker | rb | 14.9375
Profiler
nfl=# SELECT * FROM pl_profiler;
func_oid | line_number | line | exec_count | total_time | longest_time
----------+-------------+----------------------------------------------------------------------+------------+------------+--------------
99155 | 1 | | 0 | 0 | 0
99155 | 2 | DECLARE | 0 | 0 | 0
99155 | 3 | l_position VARCHAR; | 0 | 0 | 0
99155 | 4 | score INT; | 0 | 0 | 0
99155 | 5 | BEGIN | 0 | 0 | 0
99155 | 6 | score := 0; | 9299 | 5519 | 18
99155 | 7 | | 0 | 0 | 0
99155 | 8 | -- Get the position of the player | 0 | 0 | 0
99155 | 9 | SELECT position | 9299 | 114556 | 136
99155 | 10 | INTO l_position | 0 | 0 | 0
99155 | 11 | FROM player | 0 | 0 | 0
99155 | 12 | WHERE player_key = p_player_key; | 0 | 0 | 0
99155 | 13 | | 0 | 0 | 0
99155 | 14 | IF l_position = 'qb' THEN | 9299 | 7011451 | 2854
99155 | 15 | score := score + passing_score(p_player_key, p_year, p_week); | 1666 | 1591910 | 2101
99155 | 16 | score := score + rushing_score(p_player_key, p_year, p_week); | 1666 | 873194 | 744
99155 | 17 | score := score + td_score(p_player_key, p_year, p_week); | 1666 | 138214 | 320
99155 | 18 | ELSIF l_position = 'rb' THEN | 0 | 0 | 0
99155 | 19 | score := score + rushing_score(p_player_key, p_year, p_week); | 2822 | 1470068 | 961
99155 | 20 | score := score + td_score(p_player_key, p_year, p_week); | 2822 | 140201 | 802
99155 | 21 | ELSIF l_position = 'wr' THEN | 0 | 0 | 0
99155 | 22 | score := score + receiving_score(p_player_key, p_year, p_week); | 3111 | 1649303 | 1028
99155 | 23 | score := score + td_score(p_player_key, p_year, p_week); | 3111 | 158259 | 571
99155 | 24 | ELSIF l_position = 'te' THEN | 0 | 0 | 0
99155 | 25 | score := score + receiving_score(p_player_key, p_year, p_week); | 1700 | 902277 | 870
99155 | 26 | score := score + td_score(p_player_key, p_year, p_week); | 1700 | 67249 | 151
99155 | 27 | ELSE | 0 | 0 | 0
99155 | 28 | return 0; | 0 | 0 | 0
99155 | 29 | END IF; | 0 | 0 | 0
Profiler
nfl=# SELECT func_oid::regprocedure, line_number, substr(line, 0, 30),
nfl-# (total_time::numeric)/(exec_count::numeric), exec_count
nfl-# FROM pl_profiler
nfl-# WHERE exec_count > 0
nfl-# ORDER BY 4 DESC;
func_oid | line_number | substr | ?column? | exec_count
------------------------------------------------------+-------------+-------------------------------+------------------------+------------
yearly_player(integer) | 3 | RETURN QUERY SELECT DISTINC | 27455.000000000000 | 1
avg_yearly_score(character varying,integer) | 8 | FOR i IN 1..17 LOOP | 12840.711151736746 | 547
player_game_score(character varying,integer,integer) | 15 | score := score + passing | 926.8511404561824730 | 1666
avg_yearly_score(character varying,integer) | 9 | score := score + player_g | 755.1645338208409506 | 9299
player_game_score(character varying,integer,integer) | 14 | IF l_position = 'qb' THEN | 735.3543391762555113 | 9299
player_game_score(character varying,integer,integer) | 25 | score := score + receivi | 518.6929411764705882 | 1700
player_game_score(character varying,integer,integer) | 22 | score := score + receivi | 512.6878817100610736 | 3111
receiving_score(character varying,integer,integer) | 6 | SELECT r.yards/10 | 507.6599459571814592 | 4811
player_game_score(character varying,integer,integer) | 19 | score := score + rushing | 503.4840538625088590 | 2822
player_game_score(character varying,integer,integer) | 16 | score := score + rushing | 503.2094837935174070 | 1666
rushing_score(character varying,integer,integer) | 6 | SELECT r.yards/10 | 495.7384135472370766 | 4488
passing_score(character varying,integer,integer) | 11 | SELECT p.pass_yards/25 | 417.8895558223289316 | 1666
passing_score(character varying,integer,integer) | 37 | SELECT p.interceptions * -2 | 409.1992797118847539 | 1666
player_game_score(character varying,integer,integer) | 17 | score := score + td_scor | 83.6602641056422569 | 1666
passing_score(character varying,integer,integer) | 24 | SELECT p.passing * 4 | 83.1236494597839136 | 1666
player_game_score(character varying,integer,integer) | 23 | score := score + td_scor | 54.0118932819029251 | 3111
player_game_score(character varying,integer,integer) | 20 | score := score + td_scor | 53.8954642097802977 | 2822
td_score(character varying,integer,integer) | 6 | SELECT t.other * 6 | 50.4611248521346381 | 9299
player_game_score(character varying,integer,integer) | 26 | score := score + td_scor | 44.9488235294117647 | 1700
player_game_score(character varying,integer,integer) | 9 | SELECT position | 13.0637702978814926 | 9299
passing_score(character varying,integer,integer) | 19 | IF yardage_score IS NULL TH | 2.2893157262905162 | 1666
passing_score(character varying,integer,integer) | 45 | IF int_score IS NULL THEN | 2.1248499399759904 | 1666
rushing_score(character varying,integer,integer) | 14 | IF score IS NULL THEN | 2.1033868092691622 | 4488
receiving_score(character varying,integer,integer) | 14 | IF score IS NULL THEN | 2.0700478071087092 | 4811
td_score(character varying,integer,integer) | 14 | IF score IS NULL THEN | 1.9494569308527799 | 9299
Summary
● Be careful running these tools on
production systems
– They do have some performance impact
● Building the extensions are simple, but still
require a development environment
● The debugger and the profiler use the
same hooks so at the moment they can not
be used at the same time
Questions?
jimm@openscg.com
@jim_mlodgenski

More Related Content

Viewers also liked (20)

PPTX
Deploying Maximum HA Architecture With PostgreSQL
Denish Patel
 
PDF
PostgreSQL Procedural Languages: Tips, Tricks and Gotchas
Jim Mlodgenski
 
ODP
Postgresql Federation
Jim Mlodgenski
 
PDF
Materialized views in PostgreSQL
Ashutosh Bapat
 
PDF
Ashnik EnterpriseDB PostgreSQL - A real alternative to Oracle
Ashnikbiz
 
PPT
A brief introduction to PostgreSQL
Vu Hung Nguyen
 
PDF
An Introduction To PostgreSQL Triggers
Jim Mlodgenski
 
ODP
Introduction to PostgreSQL
Jim Mlodgenski
 
PDF
PostgreSQL 9.5 - Major Features
InMobi Technology
 
PPTX
Managing a 14 TB reporting datawarehouse with postgresql
Soumya Ranjan Subudhi
 
PDF
Why use PostgreSQL?
Gabriele Bartolini
 
PDF
PostgreSQL Replication Tutorial
Hans-Jürgen Schönig
 
PDF
Out of the Box Replication in Postgres 9.4(PgCon)
Denish Patel
 
PDF
Get to know PostgreSQL!
Oddbjørn Steffensen
 
PDF
PostgreSQL and MySQL
PostgreSQL Experts, Inc.
 
PDF
Out of the box replication in postgres 9.4
Denish Patel
 
PDF
The Great Debate: PostgreSQL vs MySQL
EDB
 
PDF
Really Big Elephants: PostgreSQL DW
PostgreSQL Experts, Inc.
 
PDF
Geographically Distributed PostgreSQL
mason_s
 
PDF
PostreSQL HA and DR Setup & Use Cases
Ashnikbiz
 
Deploying Maximum HA Architecture With PostgreSQL
Denish Patel
 
PostgreSQL Procedural Languages: Tips, Tricks and Gotchas
Jim Mlodgenski
 
Postgresql Federation
Jim Mlodgenski
 
Materialized views in PostgreSQL
Ashutosh Bapat
 
Ashnik EnterpriseDB PostgreSQL - A real alternative to Oracle
Ashnikbiz
 
A brief introduction to PostgreSQL
Vu Hung Nguyen
 
An Introduction To PostgreSQL Triggers
Jim Mlodgenski
 
Introduction to PostgreSQL
Jim Mlodgenski
 
PostgreSQL 9.5 - Major Features
InMobi Technology
 
Managing a 14 TB reporting datawarehouse with postgresql
Soumya Ranjan Subudhi
 
Why use PostgreSQL?
Gabriele Bartolini
 
PostgreSQL Replication Tutorial
Hans-Jürgen Schönig
 
Out of the Box Replication in Postgres 9.4(PgCon)
Denish Patel
 
Get to know PostgreSQL!
Oddbjørn Steffensen
 
PostgreSQL and MySQL
PostgreSQL Experts, Inc.
 
Out of the box replication in postgres 9.4
Denish Patel
 
The Great Debate: PostgreSQL vs MySQL
EDB
 
Really Big Elephants: PostgreSQL DW
PostgreSQL Experts, Inc.
 
Geographically Distributed PostgreSQL
mason_s
 
PostreSQL HA and DR Setup & Use Cases
Ashnikbiz
 

More from Jim Mlodgenski (6)

PDF
Strategic autovacuum
Jim Mlodgenski
 
PDF
Top 10 Mistakes When Migrating From Oracle to PostgreSQL
Jim Mlodgenski
 
PDF
Oracle postgre sql-mirgration-top-10-mistakes
Jim Mlodgenski
 
PPT
Leveraging Hadoop in your PostgreSQL Environment
Jim Mlodgenski
 
ODP
Multi-Master Replication with Slony
Jim Mlodgenski
 
ODP
Scaling PostgreSQL With GridSQL
Jim Mlodgenski
 
Strategic autovacuum
Jim Mlodgenski
 
Top 10 Mistakes When Migrating From Oracle to PostgreSQL
Jim Mlodgenski
 
Oracle postgre sql-mirgration-top-10-mistakes
Jim Mlodgenski
 
Leveraging Hadoop in your PostgreSQL Environment
Jim Mlodgenski
 
Multi-Master Replication with Slony
Jim Mlodgenski
 
Scaling PostgreSQL With GridSQL
Jim Mlodgenski
 
Ad

Recently uploaded (20)

PDF
Kit-Works Team Study_20250627_한달만에만든사내서비스키링(양다윗).pdf
Wonjun Hwang
 
PDF
What’s my job again? Slides from Mark Simos talk at 2025 Tampa BSides
Mark Simos
 
PDF
“Computer Vision at Sea: Automated Fish Tracking for Sustainable Fishing,” a ...
Edge AI and Vision Alliance
 
PDF
Future-Proof or Fall Behind? 10 Tech Trends You Can’t Afford to Ignore in 2025
DIGITALCONFEX
 
PDF
Transcript: Book industry state of the nation 2025 - Tech Forum 2025
BookNet Canada
 
PPTX
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
PDF
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PPTX
The Project Compass - GDG on Campus MSIT
dscmsitkol
 
PPTX
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
PDF
AI Agents in the Cloud: The Rise of Agentic Cloud Architecture
Lilly Gracia
 
PDF
Go Concurrency Real-World Patterns, Pitfalls, and Playground Battles.pdf
Emily Achieng
 
DOCX
Cryptography Quiz: test your knowledge of this important security concept.
Rajni Bhardwaj Grover
 
PDF
NLJUG Speaker academy 2025 - first session
Bert Jan Schrijver
 
PDF
NASA A Researcher’s Guide to International Space Station : Physical Sciences ...
Dr. PANKAJ DHUSSA
 
PDF
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
PDF
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
PPTX
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
PDF
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
PDF
LOOPS in C Programming Language - Technology
RishabhDwivedi43
 
Kit-Works Team Study_20250627_한달만에만든사내서비스키링(양다윗).pdf
Wonjun Hwang
 
What’s my job again? Slides from Mark Simos talk at 2025 Tampa BSides
Mark Simos
 
“Computer Vision at Sea: Automated Fish Tracking for Sustainable Fishing,” a ...
Edge AI and Vision Alliance
 
Future-Proof or Fall Behind? 10 Tech Trends You Can’t Afford to Ignore in 2025
DIGITALCONFEX
 
Transcript: Book industry state of the nation 2025 - Tech Forum 2025
BookNet Canada
 
COMPARISON OF RASTER ANALYSIS TOOLS OF QGIS AND ARCGIS
Sharanya Sarkar
 
Newgen 2022-Forrester Newgen TEI_13 05 2022-The-Total-Economic-Impact-Newgen-...
darshakparmar
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
The Project Compass - GDG on Campus MSIT
dscmsitkol
 
AI Penetration Testing Essentials: A Cybersecurity Guide for 2025
defencerabbit Team
 
AI Agents in the Cloud: The Rise of Agentic Cloud Architecture
Lilly Gracia
 
Go Concurrency Real-World Patterns, Pitfalls, and Playground Battles.pdf
Emily Achieng
 
Cryptography Quiz: test your knowledge of this important security concept.
Rajni Bhardwaj Grover
 
NLJUG Speaker academy 2025 - first session
Bert Jan Schrijver
 
NASA A Researcher’s Guide to International Space Station : Physical Sciences ...
Dr. PANKAJ DHUSSA
 
Mastering Financial Management in Direct Selling
Epixel MLM Software
 
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
CIFDAQ Market Wrap for the week of 4th July 2025
CIFDAQ
 
LOOPS in C Programming Language - Technology
RishabhDwivedi43
 
Ad

Debugging Your PL/pgSQL Code

  • 2. Who Am I? ● Jim Mlodgenski – [email protected] – @jim_mlodgenski ● Director – United States PostgreSQL (www.postgresql.us) ● Co-organizer of – Philly PUG (www.phlpug.org) – NYC PUG (www.nycpug.org) ● CTO, OpenSCG – www.openscg.com
  • 4. Fantasy Football ● Fantasy football is a statistical game in which players compete against each other by managing groups of real players or position units selected from American football teams.
  • 8. Business Rules ● Passing – Touchdown (4 points) – Every 25 yards (1 point) – Interception (-1 point) ● Rushing – Touchdown (6 points) – Every 10 yards (1 point) ● Receiving – Touchdown (6 points) – Every 10 yards (1 point)
  • 11. Procedures CREATE OR REPLACE FUNCTION rushing_score(p_player_key VARCHAR, p_year int, p_week int) RETURNS INT AS $$ DECLARE score INT; BEGIN -- 1 point for every 10 yards rushing SELECT r.yards/10 INTO score FROM rushing r, games g WHERE r.game_id = g.game_id AND g.year = p_year AND g.week = p_week AND r.player_key = p_player_key; IF score IS NULL THEN RETURN 0; END IF; RETURN score; END; $$ LANGUAGE plpgsql;
  • 12. Procedures CREATE OR REPLACE FUNCTION player_game_score(p_player_key VARCHAR, p_year int, p_week int) ... BEGIN score := 0; -- Get the position of the player SELECT position INTO l_position FROM player WHERE player_key = p_player_key; IF l_position = 'qb' THEN score := score + passing_score(p_player_key, p_year, p_week); score := score + rushing_score(p_player_key, p_year, p_week); score := score + td_score(p_player_key, p_year, p_week); ELSIF l_position = 'rb' THEN score := score + rushing_score(p_player_key, p_year, p_week); score := score + td_score(p_player_key, p_year, p_week); ELSIF l_position = 'wr' THEN score := score + receiving_score(p_player_key, p_year, p_week); score := score + td_score(p_player_key, p_year, p_week); ELSIF l_position = 'te' THEN score := score + receiving_score(p_player_key, p_year, p_week); score := score + td_score(p_player_key, p_year, p_week); ELSE return 0; END IF; return score; END; $$ LANGUAGE plpgsql;
  • 13. Procedures CREATE OR REPLACE FUNCTION avg_yearly_score(p_player_key VARCHAR, p_year int) RETURNS REAL AS $$ DECLARE score INT; i INT; BEGIN score := 0; FOR i IN 1..17 LOOP score := score + player_game_score(p_player_key, p_year, i); END LOOP; RETURN score/16.0; END; $$ LANGUAGE plpgsql;
  • 14. Debugging: RAISE CREATE OR REPLACE FUNCTION passing_score(p_player_key VARCHAR, p_year int, p_week int) RETURNS INT AS $$ ... BEGIN score := 0; -- 1 point for every 25 yards passing SELECT p.pass_yards/25 INTO yardage_score FROM passing p, games g WHERE p.game_id = g.game_id AND g.year = p_year AND g.week = p_week AND p.player_key = p_player_key; IF yardage_score IS NULL THEN yardage_score := 0; END IF; RAISE NOTICE 'Passing Yards Score: %', yardage_score;
  • 15. Debugging: RAISE nfl=# select passing_score('BreeDr00', 2005, 5); NOTICE: Passing Yards Score: 8 NOTICE: Passing TD Score: 4 NOTICE: Interception Score: -2 passing_score --------------- 10 (1 row)
  • 16. Debugger git://git.postgresql.org/git/pldebugger.git make USE_PGXS=1 make install USE_PGXS=1 - OR - http://community.openscg.com/se/postgresql/packages.jsp shared_preload_libraries = '$libdir/plugin_debugger' CREATE EXTENSION pldbgapi;
  • 17. Demo
  • 23. Debugging: RAISE nfl=# SELECT p.first_name, p.last_name, p.position, avg_yearly_score(p.player_key, 2006) AS score FROM player p WHERE p.player_key IN (SELECT * FROM yearly_player(2005)) AND avg_yearly_score(p.player_key, 2006) > 10 ORDER BY 4 DESC;
  • 24. Debugging: RAISE CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Passing TD Score: 8 CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Interception Score: -2 CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Passing Yards Score: 9 CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Passing TD Score: 4 CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Interception Score: 0 CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Passing Yards Score: 10 CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Passing TD Score: 8 CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Interception Score: -4 CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Passing Yards Score: 7 CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Passing TD Score: 4 CONTEXT: PL/pgSQL function player_game_score(character varying,integer,integer) line 15 at assignment PL/pgSQL function avg_yearly_score(character varying,integer) line 9 at assignment NOTICE: Interception Score: -2 ...
  • 25. Track Functions set track_functions = 'PL'; nfl=# SELECT * FROM pg_stat_user_functions; funcid | schemaname | funcname | calls | total_time | self_time --------+------------+-------------------+-------+------------+----------- 20564 | public | avg_yearly_score | 547 | 7011.25 | 13.33 20565 | public | passing_score | 1666 | 1551.862 | 1551.862 20566 | public | player_game_score | 9299 | 6997.92 | 188.718 20567 | public | receiving_score | 4811 | 2465.982 | 2465.982 20568 | public | rushing_score | 4488 | 2303.934 | 2303.934 20569 | public | td_score | 9299 | 487.424 | 487.424 20570 | public | yearly_player | 1 | 14.139 | 14.139 (7 rows)
  • 26. Profiler https://bitbucket.org/openscg/plprofiler.git make USE_PGXS=1 make install USE_PGXS=1 - OR - http://community.openscg.com/se/postgresql/packages.jsp shared_preload_libraries = '$libdir/plprofiler.so' CREATE EXTENSION plprofiler;
  • 27. Demo
  • 28. Profiler nfl=# SELECT * FROM pl_profiler; ERROR: plprofiler must be loaded and enabled STATEMENT: SELECT * FROM pl_profiler; nfl=# SELECT pl_profiler_enable(true); pl_profiler_enable -------------------- t (1 row)
  • 29. Profiler nfl=# SELECT p.first_name, p.last_name, p.position, nfl-# avg_yearly_score(p.player_key, 2006) AS score nfl-# FROM player p nfl-# WHERE p.player_key IN (SELECT * FROM yearly_player(2005)) nfl-# AND avg_yearly_score(p.player_key, 2006) > 10 nfl-# ORDER BY 4 DESC; first_name | last_name | position | score ------------+----------------+----------+--------- LaDainian | Tomlinson | rb | 22.5 Peyton | Manning | qb | 18.875 Larry | Johnson | rb | 17.875 Michael | Vick | qb | 15.875 Drew | Brees | qb | 15.75 Marc | Bulger | qb | 15.5625 Steven | Jackson | rb | 15.1875 Carson | Palmer | qb | 15.125 Willie | Parker | rb | 14.9375
  • 30. Profiler nfl=# SELECT * FROM pl_profiler; func_oid | line_number | line | exec_count | total_time | longest_time ----------+-------------+----------------------------------------------------------------------+------------+------------+-------------- 99155 | 1 | | 0 | 0 | 0 99155 | 2 | DECLARE | 0 | 0 | 0 99155 | 3 | l_position VARCHAR; | 0 | 0 | 0 99155 | 4 | score INT; | 0 | 0 | 0 99155 | 5 | BEGIN | 0 | 0 | 0 99155 | 6 | score := 0; | 9299 | 5519 | 18 99155 | 7 | | 0 | 0 | 0 99155 | 8 | -- Get the position of the player | 0 | 0 | 0 99155 | 9 | SELECT position | 9299 | 114556 | 136 99155 | 10 | INTO l_position | 0 | 0 | 0 99155 | 11 | FROM player | 0 | 0 | 0 99155 | 12 | WHERE player_key = p_player_key; | 0 | 0 | 0 99155 | 13 | | 0 | 0 | 0 99155 | 14 | IF l_position = 'qb' THEN | 9299 | 7011451 | 2854 99155 | 15 | score := score + passing_score(p_player_key, p_year, p_week); | 1666 | 1591910 | 2101 99155 | 16 | score := score + rushing_score(p_player_key, p_year, p_week); | 1666 | 873194 | 744 99155 | 17 | score := score + td_score(p_player_key, p_year, p_week); | 1666 | 138214 | 320 99155 | 18 | ELSIF l_position = 'rb' THEN | 0 | 0 | 0 99155 | 19 | score := score + rushing_score(p_player_key, p_year, p_week); | 2822 | 1470068 | 961 99155 | 20 | score := score + td_score(p_player_key, p_year, p_week); | 2822 | 140201 | 802 99155 | 21 | ELSIF l_position = 'wr' THEN | 0 | 0 | 0 99155 | 22 | score := score + receiving_score(p_player_key, p_year, p_week); | 3111 | 1649303 | 1028 99155 | 23 | score := score + td_score(p_player_key, p_year, p_week); | 3111 | 158259 | 571 99155 | 24 | ELSIF l_position = 'te' THEN | 0 | 0 | 0 99155 | 25 | score := score + receiving_score(p_player_key, p_year, p_week); | 1700 | 902277 | 870 99155 | 26 | score := score + td_score(p_player_key, p_year, p_week); | 1700 | 67249 | 151 99155 | 27 | ELSE | 0 | 0 | 0 99155 | 28 | return 0; | 0 | 0 | 0 99155 | 29 | END IF; | 0 | 0 | 0
  • 31. Profiler nfl=# SELECT func_oid::regprocedure, line_number, substr(line, 0, 30), nfl-# (total_time::numeric)/(exec_count::numeric), exec_count nfl-# FROM pl_profiler nfl-# WHERE exec_count > 0 nfl-# ORDER BY 4 DESC; func_oid | line_number | substr | ?column? | exec_count ------------------------------------------------------+-------------+-------------------------------+------------------------+------------ yearly_player(integer) | 3 | RETURN QUERY SELECT DISTINC | 27455.000000000000 | 1 avg_yearly_score(character varying,integer) | 8 | FOR i IN 1..17 LOOP | 12840.711151736746 | 547 player_game_score(character varying,integer,integer) | 15 | score := score + passing | 926.8511404561824730 | 1666 avg_yearly_score(character varying,integer) | 9 | score := score + player_g | 755.1645338208409506 | 9299 player_game_score(character varying,integer,integer) | 14 | IF l_position = 'qb' THEN | 735.3543391762555113 | 9299 player_game_score(character varying,integer,integer) | 25 | score := score + receivi | 518.6929411764705882 | 1700 player_game_score(character varying,integer,integer) | 22 | score := score + receivi | 512.6878817100610736 | 3111 receiving_score(character varying,integer,integer) | 6 | SELECT r.yards/10 | 507.6599459571814592 | 4811 player_game_score(character varying,integer,integer) | 19 | score := score + rushing | 503.4840538625088590 | 2822 player_game_score(character varying,integer,integer) | 16 | score := score + rushing | 503.2094837935174070 | 1666 rushing_score(character varying,integer,integer) | 6 | SELECT r.yards/10 | 495.7384135472370766 | 4488 passing_score(character varying,integer,integer) | 11 | SELECT p.pass_yards/25 | 417.8895558223289316 | 1666 passing_score(character varying,integer,integer) | 37 | SELECT p.interceptions * -2 | 409.1992797118847539 | 1666 player_game_score(character varying,integer,integer) | 17 | score := score + td_scor | 83.6602641056422569 | 1666 passing_score(character varying,integer,integer) | 24 | SELECT p.passing * 4 | 83.1236494597839136 | 1666 player_game_score(character varying,integer,integer) | 23 | score := score + td_scor | 54.0118932819029251 | 3111 player_game_score(character varying,integer,integer) | 20 | score := score + td_scor | 53.8954642097802977 | 2822 td_score(character varying,integer,integer) | 6 | SELECT t.other * 6 | 50.4611248521346381 | 9299 player_game_score(character varying,integer,integer) | 26 | score := score + td_scor | 44.9488235294117647 | 1700 player_game_score(character varying,integer,integer) | 9 | SELECT position | 13.0637702978814926 | 9299 passing_score(character varying,integer,integer) | 19 | IF yardage_score IS NULL TH | 2.2893157262905162 | 1666 passing_score(character varying,integer,integer) | 45 | IF int_score IS NULL THEN | 2.1248499399759904 | 1666 rushing_score(character varying,integer,integer) | 14 | IF score IS NULL THEN | 2.1033868092691622 | 4488 receiving_score(character varying,integer,integer) | 14 | IF score IS NULL THEN | 2.0700478071087092 | 4811 td_score(character varying,integer,integer) | 14 | IF score IS NULL THEN | 1.9494569308527799 | 9299
  • 32. Summary ● Be careful running these tools on production systems – They do have some performance impact ● Building the extensions are simple, but still require a development environment ● The debugger and the profiler use the same hooks so at the moment they can not be used at the same time