Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Postgres FTW 1: Postgres is just easier
http://www.slideshare.net/gisborne/postgres-is-easier
Data Types•   Boolean (!)•   Numeric    •   up to 131072 digits before decimal;        16383 digits after (MySQL: 65 digit...
Data Types•   Make your own!    CREATE TYPE inventory_item AS (    ! name            text,    ! supplier_id     integer,  ...
Custom FunctionsCREATE FUNCTION price_extension(! inventory_item,! integer)RETURNS! numericAS ! SELECT! ! $1.price * $2LAN...
Functions! (Statistical)corr(Y, X)             regr_sxx(Y, X)covar_pop(Y, X)        regr_sxy(Y, X)covar_samp(Y, X)       r...
Functions! (Statistical)                                                 MySQL:corr(Y, X)             regr_sxx(Y, X)      ...
Functions! (Text Search)•   Very fast index updates   • Search terms in context                                 (shows how...
Functions! (Text Search)•   Very fast index updates   • Search terms in context   MySQL:                                 (...
Functions! (Window Functions)•   Aggregate values from single rows•   Perform GROUP BY calculations, BUT leave rows intact
Functions! (Window Functions)
Functions! (Window Functions)Any aggregate function:    SELECT name, salary, salary / (avg(salary) OVER (PARTITION BY depn...
Functions! (Window Functions)Any aggregate function:    SELECT name, salary, salary / (avg(salary) OVER (PARTITION BY depn...
Common Table Expressions•   Like a local view; or•   Like a named subquery (or named INSERT, DELETE etc)
Common Table ExpressionsSimplify subqueries:  WITH                               SELECT  ! regional_sales AS (            ...
Common Table ExpressionsRecursive queries:  WITH RECURSIVE  ! t(n) AS (  ! ! ! VALUES (1)  ! ! UNION ALL  ! ! ! SELECT  ! ...
Common Table ExpressionsRecursive queries:  WITH RECURSIVE  ! search_graph(id, link, data, depth) AS (  ! ! ! SELECT  ! ! ...
Common Table ExpressionsRecursive queries:  WITH RECURSIVE  ! search_graph(id, link, data, depth) AS (  ! ! ! SELECT  ! ! ...
Common Table ExpressionsRecursive queries:  WITH RECURSIVE         !   !   !SELECT  ! search_graph(        !   !   !! g.id...
Common Table ExpressionsRecursive queries:  WITH RECURSIVE         !   !   !SELECT  ! search_graph(        !   !   !! g.id...
Common Table ExpressionsRecursive queries:  WITH RECURSIVE         !   !   !SELECT  ! search_graph(        !   !   !! g.id...
Common Table ExpressionsRecursive queries:  WITH RECURSIVE         !   !   !SELECT  ! search_graph(        !   !   !! g.id...
Common Table ExpressionsModifying data:  WITH  ! moved_rows AS (  ! ! DELETE  ! ! FROM  ! ! ! products  ! ! WHERE  ! ! ! "...
Small but big features
Small but big features•   Index in the background
Small but big features•   Index in the background•   Transactional schema changes
Small but big features•   Index in the background•   Transactional schema changes•   Fast schema changes
Small but big features•   Index in the background•   Transactional schema changes•   Fast schema changes    •   Drop colum...
Small but big features•   Index in the background•   Transactional schema changes•   Fast schema changes    •   Drop colum...
NoSQL?
NoSQL in your SQL (Arrays)•   Array type    CREATE TABLE sal_emp (              INSERT INTO    ! name             text,   ...
NoSQL in your SQL (Arrays)SELECT * FROM sal_emp; name |       pay_by_quarter       |                 schedule-------+-----...
NoSQL in your SQL (Arrays)SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = Bill;        schedule-----------------------...
NoSQL in your SQL (Arrays)SELECT!   buyer,!   SUM(total),!   ARRAY_AGG(order_date ORDER BY total DESC)FROM!   ordersGROUP ...
NoSQL in your SQL (HStore)Key-value store:create_table :products do |t|! t.string :name! t.hstore :data! t.timestampsendge...
NoSQL in your SQL (HStore)# Find all products that have a key of author in dataProduct.where("data ? :key", :key => author...
Use a really good languageCREATE FUNCTION tu(varchar)RETURNS setof recordAS !   size = PL.column_name(args[0]).size!   res...
FINhttp://www.slideshare.net/gisborne/postgres-is-easier                          guyren@relevantlogic.com                ...
Upcoming SlideShare
Loading in …5
×

Postgres is easier

2,518 views

Published on

A survey of some of the features Postgres has which MySQL doesn't, and which will make your life as a database developer easier

Published in: Technology
  • Be the first to comment

Postgres is easier

  1. 1. Postgres FTW 1: Postgres is just easier
  2. 2. http://www.slideshare.net/gisborne/postgres-is-easier
  3. 3. Data Types• Boolean (!)• Numeric • up to 131072 digits before decimal; 16383 digits after (MySQL: 65 digits)• Network address broadcast(192.168.1.5/24) hostmask(192.168.23.20/30)• UUID• XML• Geometric (point, line, rectangle, circle, path, polygon)• JSON (in 9.2, later in 2012)
  4. 4. Data Types• Make your own! CREATE TYPE inventory_item AS ( ! name text, ! supplier_id integer, ! price numeric); CREATE TABLE on_hand ( ! item inventory_item, ! count integer); INSERT INTO on_hand VALUES (ROW(fuzzy dice, 42, 1.99), 1000); SELECT (on_hand.item).name FROM on_hand WHERE (on_hand.item).price > 9.99;
  5. 5. Custom FunctionsCREATE FUNCTION price_extension(! inventory_item,! integer)RETURNS! numericAS ! SELECT! ! $1.price * $2LANGUAGE SQL;SELECT price_extension(item, 10) FROM on_hand;
  6. 6. Functions! (Statistical)corr(Y, X) regr_sxx(Y, X)covar_pop(Y, X) regr_sxy(Y, X)covar_samp(Y, X) regr_syy(Y, X)regr_avgx(Y, X) stddev(expression)regr_avgy(Y, X) stddev_pop(expression)regr_count(Y, X) stddev_samp(expression)regr_intercept(Y, X) variance(expression)regr_r2(Y, X) var_pop(expression)regr_slope(Y, X) var_samp(expression)
  7. 7. Functions! (Statistical) MySQL:corr(Y, X) regr_sxx(Y, X) MAX()covar_pop(Y, X) regr_sxy(Y, X) MIN()covar_samp(Y, X) regr_syy(Y, X) STD()regr_avgx(Y, X) stddev(expression) STDDEV_POP()regr_avgy(Y, X) stddev_pop(expression) STDDEV_SAMP()regr_count(Y, X) stddev_samp(expression) STDDEV()regr_intercept(Y, X) variance(expression) SUM() VAR_POP()regr_r2(Y, X) var_pop(expression) VAR_SAMP()regr_slope(Y, X) var_samp(expression) VARIANCE()
  8. 8. Functions! (Text Search)• Very fast index updates • Search terms in context (shows how your search• Proximity terms are used in• Weighting scheme context)• Stemming • Regex, substring etc• Stopwords• Modular architecture (add parsers and dictionaries)• Multilingual support
  9. 9. Functions! (Text Search)• Very fast index updates • Search terms in context MySQL: (shows how your search• Proximity terms are used in Regex, substring, etc• Weighting scheme context)• Stemming • Regex, substring etc• Stopwords• Modular architecture (add parsers and dictionaries)• Multilingual support
  10. 10. Functions! (Window Functions)• Aggregate values from single rows• Perform GROUP BY calculations, BUT leave rows intact
  11. 11. Functions! (Window Functions)
  12. 12. Functions! (Window Functions)Any aggregate function: SELECT name, salary, salary / (avg(salary) OVER (PARTITION BY depname)) FROM employee
  13. 13. Functions! (Window Functions)Any aggregate function: SELECT name, salary, salary / (avg(salary) OVER (PARTITION BY depname)) FROM employeeSpecial window functions: SELECT name, rank() OVER (PARTITION BY department_id ORDER BY hire_date ASC) FROM employee
  14. 14. Common Table Expressions• Like a local view; or• Like a named subquery (or named INSERT, DELETE etc)
  15. 15. Common Table ExpressionsSimplify subqueries: WITH SELECT ! regional_sales AS ( ! region, ! ! SELECT ! product, ! ! ! region, ! SUM(quantity) AS product_units, ! ! ! SUM(amount) AS total_sales ! SUM(amount) AS product_sales ! ! FROM FROM ! ! ! orders ! orders ! GROUP BY WHERE ! ! ! region), ! region IN ( ! top_regions AS ( ! ! SELECT ! ! SELECT ! ! ! region ! ! ! region ! ! FROM ! ! FROM ! ! ! top_regions) ! ! ! regional_sales GROUP BY ! ! WHERE ! region, ! ! ! total_sales > ( ! product; ! ! ! ! SELECT ! ! ! ! ! SUM(total_sales)/10 ! ! ! ! FROM ! ! ! ! ! regional_sales))
  16. 16. Common Table ExpressionsRecursive queries: WITH RECURSIVE ! t(n) AS ( ! ! ! VALUES (1) ! ! UNION ALL ! ! ! SELECT ! ! ! ! n+1 ! ! ! FROM ! ! ! ! t ! ! ! WHERE ! ! ! ! n < 100) SELECT ! sum(n) FROM ! t;
  17. 17. Common Table ExpressionsRecursive queries: WITH RECURSIVE ! search_graph(id, link, data, depth) AS ( ! ! ! SELECT ! ! ! ! g.id, ! ! ! ! g.link, ! ! ! ! g.data, ! ! ! ! 1 ! ! ! FROM ! ! ! ! graph g UNION ALL ! ! ! SELECT ! ! ! ! g.id, ! ! ! ! g.link, ! ! ! ! g.data, ! ! ! ! sg.depth + 1 ! ! ! FROM ! ! ! ! graph g, ! ! ! ! search_graph sg ! ! ! WHERE ! ! ! ! g.id = sg.link) SELECT * FROM search_graph;
  18. 18. Common Table ExpressionsRecursive queries: WITH RECURSIVE ! search_graph(id, link, data, depth) AS ( ! ! ! SELECT ! ! ! ! g.id, ! ! ! ! g.link, cl es! ! ! ! ! g.data, cy ! ! ! ! 1 w ith ails ! ! ! FROM ! ! ! ! graph g UNION ALL F ! ! ! SELECT ! ! ! ! g.id, ! ! ! ! g.link, ! ! ! ! g.data, ! ! ! ! sg.depth + 1 ! ! ! FROM ! ! ! ! graph g, ! ! ! ! search_graph sg ! ! ! WHERE ! ! ! ! g.id = sg.link) SELECT * FROM search_graph;
  19. 19. Common Table ExpressionsRecursive queries: WITH RECURSIVE ! ! !SELECT ! search_graph( ! ! !! g.id, ! ! id, ! ! !! g.link, ! ! link, ! ! !! g.data, ! ! data, ! ! !! sg.depth + 1, ! ! depth, ! ! !! path || g.id, ! ! path, ! ! !! g.id = ANY(path) ! ! cycle) AS ( !FROM ! ! ! SELECT ! ! ! ! graph g, ! ! ! ! g.id, ! ! ! ! search_graph sg ! ! ! ! g.link, ! ! ! WHERE ! ! ! ! g.data, ! ! ! ! g.id = sg.link AND ! ! ! ! 1, ! ! ! ! NOT cycle) ! ! ! ! ARRAY[g.id], SELECT * FROM search_graph; ! ! ! ! false ! ! ! FROM ! ! ! ! graph g UNION ALL
  20. 20. Common Table ExpressionsRecursive queries: WITH RECURSIVE ! ! !SELECT ! search_graph( ! ! !! g.id, ! ! id, ! ! !! g.link, ! ! link, ! ! !! g.data, ! ! data, ! ! !! sg.depth + 1, ! ! depth, ! ! !! path || g.id, ! ! path, ! ! !! g.id = ANY(path) ! ! cycle) AS ( !FROM ! ! ! SELECT ! ! ! ! graph g, ! ! ! ! g.id, ! ! ! ! search_graph sg ! ! ! ! g.link, ! ! ! WHERE ! ! ! ! g.data, ! ! ! ! g.id = sg.link AND ! ! ! ! 1, ! ! ! ! NOT cycle) ! ! ! ! ARRAY[g.id], SELECT * FROM search_graph; ! ! ! ! false ! ! ! FROM ! ! ! ! graph g UNION ALL
  21. 21. Common Table ExpressionsRecursive queries: WITH RECURSIVE ! ! !SELECT ! search_graph( ! ! !! g.id, ! ! id, ! ! !! g.link, ! ! link, ! ! !! g.data, ! ! data, ! ! !! sg.depth + 1, ! ! depth, ! ! !! path || g.id, ! ! path, ! ! !! g.id = ANY(path) ! ! cycle) AS ( !FROM ! ! ! SELECT ! ! ! ! graph g, ! ! ! ! g.id, ! ! ! ! search_graph sg ! ! ! ! g.link, ! ! ! WHERE ! ! ! ! g.data, ! ! ! ! g.id = sg.link AND ! ! ! ! 1, ! ! ! ! NOT cycle) ! ! ! ! ARRAY[g.id], SELECT * FROM search_graph; ! ! ! ! false ! ! ! FROM ! ! ! ! graph g UNION ALL
  22. 22. Common Table ExpressionsRecursive queries: WITH RECURSIVE ! ! !SELECT ! search_graph( ! ! !! g.id, ! ! id, ! ! !! g.link, ! ! link, ! ! !! g.data, ! ! data, ! ! !! sg.depth + 1, ! ! depth, ! ! !! path || g.id, ! ! path, ! ! !! g.id = ANY(path) ! ! cycle) AS ( !FROM ! ! ! SELECT ! ! ! ! graph g, ! ! ! ! g.id, ! ! ! ! search_graph sg ! ! ! ! g.link, ! ! ! WHERE ! ! ! ! g.data, ! ! ! ! g.id = sg.link AND ! ! ! ! 1, ! ! ! ! NOT cycle) ! ! ! ! ARRAY[g.id], SELECT * FROM search_graph; ! ! ! ! false ! ! ! FROM ! ! ! ! graph g UNION ALL
  23. 23. Common Table ExpressionsModifying data: WITH ! moved_rows AS ( ! ! DELETE ! ! FROM ! ! ! products ! ! WHERE ! ! ! "date" >= 2010-10-01 AND ! ! ! "date" < 2010-11-01 ! RETURNING *) INSERT INTO ! products_log SELECT ! * FROM ! moved_rows;
  24. 24. Small but big features
  25. 25. Small but big features• Index in the background
  26. 26. Small but big features• Index in the background• Transactional schema changes
  27. 27. Small but big features• Index in the background• Transactional schema changes• Fast schema changes
  28. 28. Small but big features• Index in the background• Transactional schema changes• Fast schema changes • Drop column instantly
  29. 29. Small but big features• Index in the background• Transactional schema changes• Fast schema changes • Drop column instantly • Add column instantly (unless default value)
  30. 30. NoSQL?
  31. 31. NoSQL in your SQL (Arrays)• Array type CREATE TABLE sal_emp ( INSERT INTO ! name text, ! sal_emp ! pay_by_quarter integer[], VALUES ( ! schedule text[][]); ! Carol, ! {20000, 25000, 25000, 25000}, INSERT INTO ! { ! sal_emp ! ! {"breakfast", "consulting"}, VALUES ( ! ! {"meeting", "lunch"} ! Bill, ! }); ! {10000, 10000, 10000, 10000}, ! { ! ! {"meeting", "lunch"}, ! ! {"training", "presentation"} ! });
  32. 32. NoSQL in your SQL (Arrays)SELECT * FROM sal_emp; name | pay_by_quarter | schedule-------+---------------------------+------------------------------------------- Bill | {10000,10000,10000,10000} | {{meeting,lunch},{training,presentation}} Carol | {20000,25000,25000,25000} | {{breakfast,consulting},{meeting,lunch}}(2 rows)SELECT name FROM sal_emp WHERE pay_by_quarter[1] <> pay_by_quarter[2]; name------- Carol(1 row)
  33. 33. NoSQL in your SQL (Arrays)SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = Bill; schedule------------------------ {{meeting},{training}}(1 row)SELECT * FROM sal_emp WHERE 10000 = ANY (pay_by_quarter);ARRAY[1,4,3] @> ARRAY[3,1]
  34. 34. NoSQL in your SQL (Arrays)SELECT! buyer,! SUM(total),! ARRAY_AGG(order_date ORDER BY total DESC)FROM! ordersGROUP BY! buyer;buyer | sum | array_agg------+------+-------------------------------------------------------------------Alice | 1057 | {2009-05-08,2009-08-15,2009-03-25,2009-08-16}Bob | 905 | {2009-02-10,2009-01-29,2009-08-17,2009-05-12,2009-08-22,2009-05-28}Carol | 1118 | {2009-04-28,2009-09-01,2009-03-30,2009-06-27-01-10,2009-09-06}Dave | 1239 | {2009-05-28,2009-07-27,2009-02-07,2009-07-15,2009-08-27}Eve | 1222 | {2009-02-01,2009-08-14,2009-09-26,2009-04-07-10-02}(5 rows)
  35. 35. NoSQL in your SQL (HStore)Key-value store:create_table :products do |t|! t.string :name! t.hstore :data! t.timestampsendgem install activerecord-postgres-hstoreProduct.create(! name: "Geek Love: A Novel", data: {author => Katherine Dunn, pages => 368, category => fiction})Product.last.data[category] # => fiction
  36. 36. NoSQL in your SQL (HStore)# Find all products that have a key of author in dataProduct.where("data ? :key", :key => author)# Find all products that have a pages and 368 key value pair in dataProduct.where("data @> (:key => :value)", :key => pages, :value => 368)# Find all products that dont have a key value pair pages and 999 in dataProduct.where("not data @> (:key => :value)", :key => pages, :value => 999)# Find all products having key author and value like ba in dataProduct.where("data -> :key LIKE :value", :key => author, :value => "%Kat%")
  37. 37. Use a really good languageCREATE FUNCTION tu(varchar)RETURNS setof recordAS ! size = PL.column_name(args[0]).size! res = nil! PL::Plan.new("select * from #{args[0]}", block => 50).each do |row|! ! if res.nil?! ! ! res = row.values! ! else! ! ! res.concat row.values! ! ! yield res! ! ! res = nil! ! end! end! if res! ! res.concat Array.new(size)! ! yield res! end language plruby;CREATE FUNCTION
  38. 38. FINhttp://www.slideshare.net/gisborne/postgres-is-easier guyren@relevantlogic.com http://relevantlogic.com

×