SlideShare una empresa de Scribd logo
1 de 41
SQL Top-N
and Pagination Pattern
     Session 403

   Maxym Kharchenko
What is top-N


• Give me the top 10 salaries in the “Sales” dept
• Give me the top 10 best selling books
• Give me the 10 latest orders
Lolcats!
What is top-N



SELECT picture
                            “The internet”
FROM images
WHERE subject=‘lolcats’
/
sorted by: funny
                                “Lolcats”


                          view more: next >
Setup
SQL> @desc cities
 Name                           Null?      Type
 --------------------------     --------   ---------------
 NAME                           NOT NULL   VARCHAR2(100)
 STATE                          NOT NULL   VARCHAR2(100)
 POPULATION                     NOT NULL   NUMBER

PCTFREE 99 PCTUSED 1

http://www.census.gov
Naïve Top-N
 Give me the top 5 cities by population

                            NAME                      Pop
SELECT name, population
                            ---------------------- ------
FROM cities
                            Robertsdale city        5,276
WHERE rownum <= 5           Glen Allen town (pt.)     458
ORDER BY population DESC;   Boligee town              328
                            Riverview town            184
                            Altoona town (pt.)         30


Statistics
  7 consistent gets
Naïve Top-N explained




-----------------------------------------------------------------
| Id | Operation            | Name   | Rows | Bytes | Time      |
-----------------------------------------------------------------
|   0 | SELECT STATEMENT    |        |     5 |   110 | 00:00:01 |
|   1 | SORT ORDER BY       |        |     5 |   110 | 00:00:01 |
|* 2 |    COUNT STOPKEY     |        |       |       |          |
|   3 |    TABLE ACCESS FULL| CITIES |    10 |   220 | 00:00:01 |
-----------------------------------------------------------------
Correct top-N query
SELECT name, population    SELECT * FROM (
FROM cities                  SELECT name, population
ORDER BY population DESC     FROM cities
FETCH FIRST 5 ROWS ONLY      ORDER BY population DESC
                           ) WHERE rownum <= 5



    >= 12c                     <= 11g
Correct top-N query:
          Execution
                             NAME                        Pop
SELECT * FROM (              -------------------- ----------
  SELECT name, population    Los Angeles city      3,792,621
  FROM cities                Chicago city (pt.)    2,695,598
                             Chicago city (pt.)    2,695,598
  ORDER BY population DESC   Chicago city          2,695,598
) WHERE rownum <= 5;         New York city (pt.)   2,504,700




Statistics
  56024 consistent gets
Reading, filtering
           and sorting



---------------------------------------------------------------------
| Id | Operation                | Name   | Rows |TempSpc| Time      |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT        |        |     5 |       | 00:01:58 |
|* 1 | COUNT STOPKEY            |        |       |       |          |
|   2 |   VIEW                  |        | 56072 |       | 00:01:58 |
|* 3 |     SORT ORDER BY STOPKEY|        | 56072 | 1768K| 00:01:58 |
|   4 |     TABLE ACCESS FULL   | CITIES | 56072 |       | 00:01:54 |
---------------------------------------------------------------------
Reading, filtering
             and sorting


----------------------------------------------------------------------
| Id | Operation                | Name    | Rows |TempSpc| Time      |
----------------------------------------------------------------------
|   0 | SELECT STATEMENT        |         |     5 |       | 00:01:58 |
|* 1 | COUNT STOPKEY            |         |       |       |          |
|   2 |   VIEW                  |         | 56072 |       | 00:01:58 |
|* 3 |     SORT ORDER BY STOPKEY|         | 56072 | 1768K| 00:01:58 |
|   4 |     TABLE ACCESS FULL   | O_CITIES| 56072 |       | 00:01:54 |
----------------------------------------------------------------------
Proper data structure
Ordered By: Population



                 CREATE INDEX i_pop ON cities(population);

--------------------------------------------------------------------
| Id | Operation                       | Name   | Rows | Time      |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT               |        |     5 | 00:00:01 |
|* 1 | COUNT STOPKEY                   |        |       |          |
|   2 |   VIEW                         |        |    10 | 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID | CITIES | 56072 | 00:00:01 |
|   4 |     INDEX RANGE SCAN DESCENDING| I_POP |     10 | 00:00:01 |
--------------------------------------------------------------------

                                  Statistics
                                    12 consistent gets
Why indexes work
Ordered By: Population



                 CREATE INDEX i_pop ON cities(population);



• Colocation
• Can stop after reading N rows
• No Sort
More elaborate top-N
  Give me the top 5 cities by population in Florida
                             NAME                        Pop
SELECT * FROM (
                             -------------------- ----------
  SELECT name, population    Jacksonville city       821,784
  FROM cities                Miami city              399,457
                             Tampa city              335,709
  WHERE state='Florida'
                             St. Petersburg city     244,769
  ORDER BY population DESC   Orlando city            238,300
) WHERE rownum <= 5;

                             Statistics
                               264 consistent gets
Uncertain nature
            of filtering
Ordered By: Population




   WHERE state='Florida'        WHERE state='Florida'
  ORDER BY population DESC     ORDER BY population DESC
) WHERE rownum <= 5;         ) WHERE rownum <= 200;


Statistics                   Statistics
264 consistent gets          19747 consistent gets
Multi column indexes
  CREATE INDEX i_state_pop ON cities(state, population);

                                        where state=‘FL’

    State     AL    AK    AZ     CO           FL           MA WA

Population



             *NOT* Ordered by:        Ordered By:
             Population               Population
Multicolumn indexes
-------------------------------------------------------------------------
| Id | Operation                       | Name        | Rows | Time      |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |             |     5 | 00:00:01 |
|* 1 | COUNT STOPKEY                   |             |       |          |
|   2 |   VIEW                         |             |    11 | 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID | CITIES      | 1099 | 00:00:01 |
|* 4 |      INDEX RANGE SCAN DESCENDING| I_STATE_POP |    11 | 00:00:01 |
-------------------------------------------------------------------------

Predicate Information (identified by operation id):

  1 - filter(ROWNUM<=5)
  4 - access("STATE"='Florida')


                              Statistics
                                12 consistent gets
Trips to the table
-------------------------------------------------------------------------
| Id | Operation                       | Name        | Rows | Time      |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |             |     5 | 00:00:01 |
|* 1 | COUNT STOPKEY                   |             |       |          |
|   2 |   VIEW                         |             |    11 | 00:00:01 |
|   3 |    TABLE ACCESS BY INDEX ROWID | CITIES      | 1099 | 00:00:01 |
|* 4 |      INDEX RANGE SCAN DESCENDING| I_STATE_POP |    11 | 00:00:01 |
-------------------------------------------------------------------------

Predicate Information (identified by operation id):

  1 - filter(ROWNUM<=5)
  4 - access("STATE"='Florida')


                                  Statistics
                                    12 consistent gets
Index range scan:
   cost math


                         ~4

                       ~10
                       500
               Window: 500 records
Covering index
 CREATE INDEX i_state_pop                CREATE INDEX i_state_pop_c
 ON cities                               ON cities
   (state, population);                    (state, population, name);


 Statistics                              Statistics
   12 consistent gets                      7 consistent gets

--------------------------------------------------------------------------
| Id | Operation                      | Name          | Rows | Time      |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |               |     5 | 00:00:01 |
|* 1 | COUNT STOPKEY                  |               |       |          |
|   2 |   VIEW                        |               |    10 | 00:00:01 |
|* 3 |     INDEX RANGE SCAN DESCENDING| I_STATE_POP_C |   506 | 00:00:01 |
--------------------------------------------------------------------------
Ideal top-N

• Use the index
• Make the best index
• And read only from the index
Less than ideal top-N

• Effect of query conditions

• Effect of deletes and updates

• Technicalities
Condition better!
CREATE TABLE orders (
 …
 active char(1) NOT NULL CHECK (active IN ('Y', 'N'))


WHERE active != 'N'               WHERE active = 'Y'
  ORDER BY order_date DESC          ORDER BY order_date DESC
) WHERE rownum <= 10;             ) WHERE rownum <= 10;


Statistics                        Statistics
12345 consistent gets             10 consistent gets
Trade WHERE
           for ORDER BY
CREATE INDEX t_idx ON t(a, b, c);
SELECT * FROM (SELECT * FROM t WHERE a=12 ORDER BY c)
WHERE rownum <= 10;

WHERE a=12 ORDER BY c           Statistics
                                  1200 consistent gets
WHERE a=12 ORDER BY b, c        Statistics
                                  12 consistent gets
WHERE a=12 AND b=0              Statistics
ORDER BY c                        12 consistent gets
Tolerate filtering

SELECT * FROM (
  SELECT name, population
  FROM cities
  WHERE state != 'Florida'
  ORDER BY population DESC
) WHERE rownum <= 10;

                             Statistics
                               28 consistent gets
Tolerate filtering
--------------------------------------------------------------------
| Id | Operation                       | Name   | Rows | Time       |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT               |        |    11 | 00:00:01 |
|* 1 | COUNT STOPKEY                   |        |       |           |
|   2 |   VIEW                         |        |    11 | 00:00:01 |
|* 3 |     TABLE ACCESS BY INDEX ROWID | CITIES | 55566 | 00:00:01 |
|   4 |     INDEX RANGE SCAN DESCENDING| I_POP |     12 | 00:00:01 |
-------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM<=10)
   3 - filter("STATE"<>'Florida')
Updates and Deletes
SQL> @desc cities2
  Name                    Null?      Type
 ----------------------   --------   ----------------
 NAME                     NOT NULL   VARCHAR2(100)
 STATE                    NOT NULL   VARCHAR2(100)
 POPULATION               NOT NULL   NUMBER
 BUDGET_SURPLUS           NOT NULL   VARCHAR2(1)


CREATE INDEX i2_pop
ON cities2(budget_surplus, population, name);
Updates and Deletes
SELECT * FROM (
  SELECT name, population FROM cities2
  WHERE budget_surplus='Y' ORDER BY population DESC
) WHERE rownum <= 5;

-------------------------------------------------------------------
| Id | Operation                      | Name   | Rows | Time      |
-------------------------------------------------------------------
|   0 | SELECT STATEMENT              |        |     5 | 00:00:01 |
|* 1 | COUNT STOPKEY                  |        |       |          |
|   2 |   VIEW                        |        |    12 | 00:00:01 |
|* 3 |     INDEX RANGE SCAN DESCENDING| I2_POP | 56067 | 00:00:01 |
-------------------------------------------------------------------

                                   Statistics
                                     7 consistent gets
Updates and Deletes
UPDATE cities2 SET budget_surplus='N' WHERE rowid IN (
 SELECT * FROM (
   SELECT rowid FROM cities2 ORDER BY population DESC
 ) WHERE rownum <= 200);

-------------------------------------------------------------------
| Id | Operation                      | Name   | Rows | Time      |
-------------------------------------------------------------------
|   0 | SELECT STATEMENT              |        |     5 | 00:00:01 |
|* 1 | COUNT STOPKEY                  |        |       |          |
|   2 |   VIEW                        |        |    12 | 00:00:01 |
|* 3 |     INDEX RANGE SCAN DESCENDING| I2_POP | 56067 | 00:00:01 |
-------------------------------------------------------------------

                             Statistics
                               207 consistent gets
Updates and Deletes
Updates and Deletes
ALTER TABLE cities2 ADD (version number default 0 NOT NULL);

CREATE INDEX i2_vpop
 ON cities2(budget_surplus, version, population);

UPDATE cities2 SET version=1
WHERE budget_surplus='Y' AND version=0;

 Budget_surplus
                              Y   Y
 Budget_surplus
        Version
                              0
                              Y                 1
     Population
Updates and Deletes
SELECT * FROM (
  SELECT name, population FROM cities2
  WHERE budget_surplus='Y' AND version=1
  ORDER BY population DESC
) WHERE rownum <= 5;
--------------------------------------------------------------------
| Id | Operation                      | Name    | Rows | Time      |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT              |         |     1 | 00:00:01 |
|* 1 | COUNT STOPKEY                  |         |       |          |
|   2 |   VIEW                        |         |     1 | 00:00:01 |
|* 3 |     INDEX RANGE SCAN DESCENDING| I2_VPOP |     1 | 00:00:01 |
--------------------------------------------------------------------

                                    Statistics
                                      9 consistent gets
Pagination
SELECT * FROM (              SELECT * FROM (
  SELECT name, population      SELECT * FROM (
  FROM cities                    SELECT name, population,
  WHERE state='Florida'           rownum AS rn
  ORDER BY population DESC       FROM cities
) WHERE rownum <= 10;            WHERE state='Florida'
                                 ORDER BY population DESC
                               ) WHERE rownum <= 20
                             ) WHERE rn > 10;
Dumb Pagination
) WHERE rownum <= 20   Statistics
) WHERE rn > 10;         22 consistent gets

) WHERE rownum <= 30   Statistics
) WHERE rn > 20;         32 consistent gets
Smart pagination
SELECT * FROM (                SELECT * FROM (
  SELECT * FROM (                SELECT name, population
    SELECT name, population,     FROM cities
     rownum AS rn                WHERE state='Florida'
    FROM cities                   AND population < 154750
    WHERE state='Florida'        ORDER BY population DESC
    ORDER BY population DESC   ) WHERE rownum <= 10;
  ) WHERE rownum <= 20
) WHERE rn > 10;

Statistics                     Statistics
  22 consistent gets             12 consistent gets
Top-N with joins: Rules

• ORDER BY only the LEADING table

• Use NESTED LOOPS

• Build indexes for STREAMING
Top-N with joins
SELECT * FROM (                Driving   Filter      state
                               table:
  SELECT c.name as city,                 Order By population
   c.population, s.capital               Join       state_id
  FROM cities c, states s                Select      name

  WHERE c.state_id = s.id
   AND c.state='Florida'
  ORDER BY c.population DESC
                               Joined to Join          id
) WHERE rownum <= 5            table:    Select     capital
/
Top-N with joins: Good
-------------------------------------------------------
| Id | Operation            | Name | Rows | Time      |
-------------------------------------------------------
|   0 | SELECT STATEMENT    |      |     5 | 00:00:13 |
|* 1 | COUNT STOPKEY        |      |       |          |
|   2 |   VIEW              |      |    10 | 00:00:13 |
|   3 |    NESTED LOOPS     |      |    10 | 00:00:13 |
|* 4 |      INDEX RANGE SCAN| I_C |    506 | 00:00:07 |
|* 5 |      INDEX RANGE SCAN| I_S |      1 | 00:00:01 |
-------------------------------------------------------
Top-N with joins: Bad
-----------------------------------------------------------
| Id | Operation                | Name | Rows | Time      |
-----------------------------------------------------------
|   0 | SELECT STATEMENT        |      |     5 | 00:00:07 |
|* 1 | COUNT STOPKEY            |      |       |          |
|   2 |   VIEW                  |      |    10 | 00:00:07 |
|* 3 |     SORT ORDER BY STOPKEY|      |    10 | 00:00:07 |
|* 4 |      HASH JOIN           |      |    10 | 00:00:07 |
|* 5 |       INDEX RANGE SCAN   | I_C |    506 | 00:00:07 |
|* 6 |       INDEX RANGE SCAN   | I_S |      1 | 00:00:01 |
-----------------------------------------------------------
Gotchas?




     TMI
“Too many indexes”
Thank you!

Más contenido relacionado

Similar a SQL Top-N and pagination pattern (IOUG)

Sydney Oracle Meetup - access paths
Sydney Oracle Meetup - access pathsSydney Oracle Meetup - access paths
Sydney Oracle Meetup - access paths
paulguerin
 
Writing efficient sql
Writing efficient sqlWriting efficient sql
Writing efficient sql
j9soto
 
db tech showcase Tokyo 2014 - L36 - JPOUG : SQLチューニング総合診療所 ケースファイルX
db tech showcase Tokyo 2014 - L36 - JPOUG : SQLチューニング総合診療所 ケースファイルXdb tech showcase Tokyo 2014 - L36 - JPOUG : SQLチューニング総合診療所 ケースファイルX
db tech showcase Tokyo 2014 - L36 - JPOUG : SQLチューニング総合診療所 ケースファイルX
Hiroshi Sekiguchi
 
NOCOUG_201311_Fine_Tuning_Execution_Plans.pdf
NOCOUG_201311_Fine_Tuning_Execution_Plans.pdfNOCOUG_201311_Fine_Tuning_Execution_Plans.pdf
NOCOUG_201311_Fine_Tuning_Execution_Plans.pdf
cookie1969
 
Postgres performance for humans
Postgres performance for humansPostgres performance for humans
Postgres performance for humans
Craig Kerstiens
 
Oracle Diagnostics : Explain Plans (Simple)
Oracle Diagnostics : Explain Plans (Simple)Oracle Diagnostics : Explain Plans (Simple)
Oracle Diagnostics : Explain Plans (Simple)
Hemant K Chitale
 

Similar a SQL Top-N and pagination pattern (IOUG) (20)

SQLチューニング総合診療Oracle CloudWorld出張所
SQLチューニング総合診療Oracle CloudWorld出張所SQLチューニング総合診療Oracle CloudWorld出張所
SQLチューニング総合診療Oracle CloudWorld出張所
 
A few things about the Oracle optimizer - 2013
A few things about the Oracle optimizer - 2013A few things about the Oracle optimizer - 2013
A few things about the Oracle optimizer - 2013
 
Managing Statistics for Optimal Query Performance
Managing Statistics for Optimal Query PerformanceManaging Statistics for Optimal Query Performance
Managing Statistics for Optimal Query Performance
 
Dbms plan - A swiss army knife for performance engineers
Dbms plan - A swiss army knife for performance engineersDbms plan - A swiss army knife for performance engineers
Dbms plan - A swiss army knife for performance engineers
 
Window functions in MariaDB 10.2
Window functions in MariaDB 10.2Window functions in MariaDB 10.2
Window functions in MariaDB 10.2
 
Postgres Performance for Humans
Postgres Performance for HumansPostgres Performance for Humans
Postgres Performance for Humans
 
Sydney Oracle Meetup - access paths
Sydney Oracle Meetup - access pathsSydney Oracle Meetup - access paths
Sydney Oracle Meetup - access paths
 
Do You Know The 11g Plan?
Do You Know The 11g Plan?Do You Know The 11g Plan?
Do You Know The 11g Plan?
 
Writing efficient sql
Writing efficient sqlWriting efficient sql
Writing efficient sql
 
Modern query optimisation features in MySQL 8.
Modern query optimisation features in MySQL 8.Modern query optimisation features in MySQL 8.
Modern query optimisation features in MySQL 8.
 
Oracle sql high performance tuning
Oracle sql high performance tuningOracle sql high performance tuning
Oracle sql high performance tuning
 
MySQL and GIS Programming
MySQL and GIS ProgrammingMySQL and GIS Programming
MySQL and GIS Programming
 
Oracle Query Tuning Tips - Get it Right the First Time
Oracle Query Tuning Tips - Get it Right the First TimeOracle Query Tuning Tips - Get it Right the First Time
Oracle Query Tuning Tips - Get it Right the First Time
 
db tech showcase Tokyo 2014 - L36 - JPOUG : SQLチューニング総合診療所 ケースファイルX
db tech showcase Tokyo 2014 - L36 - JPOUG : SQLチューニング総合診療所 ケースファイルXdb tech showcase Tokyo 2014 - L36 - JPOUG : SQLチューニング総合診療所 ケースファイルX
db tech showcase Tokyo 2014 - L36 - JPOUG : SQLチューニング総合診療所 ケースファイルX
 
Randolf Geist – IT-Tage 2015 – Oracle Parallel Execution – Analyse und Troubl...
Randolf Geist – IT-Tage 2015 – Oracle Parallel Execution – Analyse und Troubl...Randolf Geist – IT-Tage 2015 – Oracle Parallel Execution – Analyse und Troubl...
Randolf Geist – IT-Tage 2015 – Oracle Parallel Execution – Analyse und Troubl...
 
Informix Warehouse Accelerator (IWA) features in version 12.1
Informix Warehouse Accelerator (IWA) features in version 12.1Informix Warehouse Accelerator (IWA) features in version 12.1
Informix Warehouse Accelerator (IWA) features in version 12.1
 
NOCOUG_201311_Fine_Tuning_Execution_Plans.pdf
NOCOUG_201311_Fine_Tuning_Execution_Plans.pdfNOCOUG_201311_Fine_Tuning_Execution_Plans.pdf
NOCOUG_201311_Fine_Tuning_Execution_Plans.pdf
 
Postgres performance for humans
Postgres performance for humansPostgres performance for humans
Postgres performance for humans
 
Oracle Diagnostics : Explain Plans (Simple)
Oracle Diagnostics : Explain Plans (Simple)Oracle Diagnostics : Explain Plans (Simple)
Oracle Diagnostics : Explain Plans (Simple)
 
E34 : [JPOUG Presents] Oracle Database の隠されている様々な謎を解くセッション「なーんでだ?」再び @ db tec...
E34 : [JPOUG Presents] Oracle Database の隠されている様々な謎を解くセッション「なーんでだ?」再び @ db tec...E34 : [JPOUG Presents] Oracle Database の隠されている様々な謎を解くセッション「なーんでだ?」再び @ db tec...
E34 : [JPOUG Presents] Oracle Database の隠されている様々な謎を解くセッション「なーんでだ?」再び @ db tec...
 

Último

Último (20)

🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 

SQL Top-N and pagination pattern (IOUG)

  • 1. SQL Top-N and Pagination Pattern Session 403 Maxym Kharchenko
  • 2. What is top-N • Give me the top 10 salaries in the “Sales” dept • Give me the top 10 best selling books • Give me the 10 latest orders
  • 4. What is top-N SELECT picture “The internet” FROM images WHERE subject=‘lolcats’ / sorted by: funny “Lolcats” view more: next >
  • 5. Setup SQL> @desc cities Name Null? Type -------------------------- -------- --------------- NAME NOT NULL VARCHAR2(100) STATE NOT NULL VARCHAR2(100) POPULATION NOT NULL NUMBER PCTFREE 99 PCTUSED 1 http://www.census.gov
  • 6. Naïve Top-N Give me the top 5 cities by population NAME Pop SELECT name, population ---------------------- ------ FROM cities Robertsdale city 5,276 WHERE rownum <= 5 Glen Allen town (pt.) 458 ORDER BY population DESC; Boligee town 328 Riverview town 184 Altoona town (pt.) 30 Statistics 7 consistent gets
  • 7. Naïve Top-N explained ----------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Time | ----------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 110 | 00:00:01 | | 1 | SORT ORDER BY | | 5 | 110 | 00:00:01 | |* 2 | COUNT STOPKEY | | | | | | 3 | TABLE ACCESS FULL| CITIES | 10 | 220 | 00:00:01 | -----------------------------------------------------------------
  • 8. Correct top-N query SELECT name, population SELECT * FROM ( FROM cities SELECT name, population ORDER BY population DESC FROM cities FETCH FIRST 5 ROWS ONLY ORDER BY population DESC ) WHERE rownum <= 5 >= 12c <= 11g
  • 9. Correct top-N query: Execution NAME Pop SELECT * FROM ( -------------------- ---------- SELECT name, population Los Angeles city 3,792,621 FROM cities Chicago city (pt.) 2,695,598 Chicago city (pt.) 2,695,598 ORDER BY population DESC Chicago city 2,695,598 ) WHERE rownum <= 5; New York city (pt.) 2,504,700 Statistics 56024 consistent gets
  • 10. Reading, filtering and sorting --------------------------------------------------------------------- | Id | Operation | Name | Rows |TempSpc| Time | --------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | | 00:01:58 | |* 1 | COUNT STOPKEY | | | | | | 2 | VIEW | | 56072 | | 00:01:58 | |* 3 | SORT ORDER BY STOPKEY| | 56072 | 1768K| 00:01:58 | | 4 | TABLE ACCESS FULL | CITIES | 56072 | | 00:01:54 | ---------------------------------------------------------------------
  • 11. Reading, filtering and sorting ---------------------------------------------------------------------- | Id | Operation | Name | Rows |TempSpc| Time | ---------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | | 00:01:58 | |* 1 | COUNT STOPKEY | | | | | | 2 | VIEW | | 56072 | | 00:01:58 | |* 3 | SORT ORDER BY STOPKEY| | 56072 | 1768K| 00:01:58 | | 4 | TABLE ACCESS FULL | O_CITIES| 56072 | | 00:01:54 | ----------------------------------------------------------------------
  • 12. Proper data structure Ordered By: Population CREATE INDEX i_pop ON cities(population); -------------------------------------------------------------------- | Id | Operation | Name | Rows | Time | -------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 00:00:01 | |* 1 | COUNT STOPKEY | | | | | 2 | VIEW | | 10 | 00:00:01 | | 3 | TABLE ACCESS BY INDEX ROWID | CITIES | 56072 | 00:00:01 | | 4 | INDEX RANGE SCAN DESCENDING| I_POP | 10 | 00:00:01 | -------------------------------------------------------------------- Statistics 12 consistent gets
  • 13. Why indexes work Ordered By: Population CREATE INDEX i_pop ON cities(population); • Colocation • Can stop after reading N rows • No Sort
  • 14. More elaborate top-N Give me the top 5 cities by population in Florida NAME Pop SELECT * FROM ( -------------------- ---------- SELECT name, population Jacksonville city 821,784 FROM cities Miami city 399,457 Tampa city 335,709 WHERE state='Florida' St. Petersburg city 244,769 ORDER BY population DESC Orlando city 238,300 ) WHERE rownum <= 5; Statistics 264 consistent gets
  • 15. Uncertain nature of filtering Ordered By: Population WHERE state='Florida' WHERE state='Florida' ORDER BY population DESC ORDER BY population DESC ) WHERE rownum <= 5; ) WHERE rownum <= 200; Statistics Statistics 264 consistent gets 19747 consistent gets
  • 16. Multi column indexes CREATE INDEX i_state_pop ON cities(state, population); where state=‘FL’ State AL AK AZ CO FL MA WA Population *NOT* Ordered by: Ordered By: Population Population
  • 17. Multicolumn indexes ------------------------------------------------------------------------- | Id | Operation | Name | Rows | Time | ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 00:00:01 | |* 1 | COUNT STOPKEY | | | | | 2 | VIEW | | 11 | 00:00:01 | | 3 | TABLE ACCESS BY INDEX ROWID | CITIES | 1099 | 00:00:01 | |* 4 | INDEX RANGE SCAN DESCENDING| I_STATE_POP | 11 | 00:00:01 | ------------------------------------------------------------------------- Predicate Information (identified by operation id): 1 - filter(ROWNUM<=5) 4 - access("STATE"='Florida') Statistics 12 consistent gets
  • 18. Trips to the table ------------------------------------------------------------------------- | Id | Operation | Name | Rows | Time | ------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 00:00:01 | |* 1 | COUNT STOPKEY | | | | | 2 | VIEW | | 11 | 00:00:01 | | 3 | TABLE ACCESS BY INDEX ROWID | CITIES | 1099 | 00:00:01 | |* 4 | INDEX RANGE SCAN DESCENDING| I_STATE_POP | 11 | 00:00:01 | ------------------------------------------------------------------------- Predicate Information (identified by operation id): 1 - filter(ROWNUM<=5) 4 - access("STATE"='Florida') Statistics 12 consistent gets
  • 19. Index range scan: cost math ~4 ~10 500 Window: 500 records
  • 20. Covering index CREATE INDEX i_state_pop CREATE INDEX i_state_pop_c ON cities ON cities (state, population); (state, population, name); Statistics Statistics 12 consistent gets 7 consistent gets -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 00:00:01 | |* 1 | COUNT STOPKEY | | | | | 2 | VIEW | | 10 | 00:00:01 | |* 3 | INDEX RANGE SCAN DESCENDING| I_STATE_POP_C | 506 | 00:00:01 | --------------------------------------------------------------------------
  • 21. Ideal top-N • Use the index • Make the best index • And read only from the index
  • 22. Less than ideal top-N • Effect of query conditions • Effect of deletes and updates • Technicalities
  • 23. Condition better! CREATE TABLE orders ( … active char(1) NOT NULL CHECK (active IN ('Y', 'N')) WHERE active != 'N' WHERE active = 'Y' ORDER BY order_date DESC ORDER BY order_date DESC ) WHERE rownum <= 10; ) WHERE rownum <= 10; Statistics Statistics 12345 consistent gets 10 consistent gets
  • 24. Trade WHERE for ORDER BY CREATE INDEX t_idx ON t(a, b, c); SELECT * FROM (SELECT * FROM t WHERE a=12 ORDER BY c) WHERE rownum <= 10; WHERE a=12 ORDER BY c Statistics 1200 consistent gets WHERE a=12 ORDER BY b, c Statistics 12 consistent gets WHERE a=12 AND b=0 Statistics ORDER BY c 12 consistent gets
  • 25. Tolerate filtering SELECT * FROM ( SELECT name, population FROM cities WHERE state != 'Florida' ORDER BY population DESC ) WHERE rownum <= 10; Statistics 28 consistent gets
  • 26. Tolerate filtering -------------------------------------------------------------------- | Id | Operation | Name | Rows | Time | -------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 11 | 00:00:01 | |* 1 | COUNT STOPKEY | | | | | 2 | VIEW | | 11 | 00:00:01 | |* 3 | TABLE ACCESS BY INDEX ROWID | CITIES | 55566 | 00:00:01 | | 4 | INDEX RANGE SCAN DESCENDING| I_POP | 12 | 00:00:01 | ------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM<=10) 3 - filter("STATE"<>'Florida')
  • 27. Updates and Deletes SQL> @desc cities2 Name Null? Type ---------------------- -------- ---------------- NAME NOT NULL VARCHAR2(100) STATE NOT NULL VARCHAR2(100) POPULATION NOT NULL NUMBER BUDGET_SURPLUS NOT NULL VARCHAR2(1) CREATE INDEX i2_pop ON cities2(budget_surplus, population, name);
  • 28. Updates and Deletes SELECT * FROM ( SELECT name, population FROM cities2 WHERE budget_surplus='Y' ORDER BY population DESC ) WHERE rownum <= 5; ------------------------------------------------------------------- | Id | Operation | Name | Rows | Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 00:00:01 | |* 1 | COUNT STOPKEY | | | | | 2 | VIEW | | 12 | 00:00:01 | |* 3 | INDEX RANGE SCAN DESCENDING| I2_POP | 56067 | 00:00:01 | ------------------------------------------------------------------- Statistics 7 consistent gets
  • 29. Updates and Deletes UPDATE cities2 SET budget_surplus='N' WHERE rowid IN ( SELECT * FROM ( SELECT rowid FROM cities2 ORDER BY population DESC ) WHERE rownum <= 200); ------------------------------------------------------------------- | Id | Operation | Name | Rows | Time | ------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 00:00:01 | |* 1 | COUNT STOPKEY | | | | | 2 | VIEW | | 12 | 00:00:01 | |* 3 | INDEX RANGE SCAN DESCENDING| I2_POP | 56067 | 00:00:01 | ------------------------------------------------------------------- Statistics 207 consistent gets
  • 31. Updates and Deletes ALTER TABLE cities2 ADD (version number default 0 NOT NULL); CREATE INDEX i2_vpop ON cities2(budget_surplus, version, population); UPDATE cities2 SET version=1 WHERE budget_surplus='Y' AND version=0; Budget_surplus Y Y Budget_surplus Version 0 Y 1 Population
  • 32. Updates and Deletes SELECT * FROM ( SELECT name, population FROM cities2 WHERE budget_surplus='Y' AND version=1 ORDER BY population DESC ) WHERE rownum <= 5; -------------------------------------------------------------------- | Id | Operation | Name | Rows | Time | -------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 00:00:01 | |* 1 | COUNT STOPKEY | | | | | 2 | VIEW | | 1 | 00:00:01 | |* 3 | INDEX RANGE SCAN DESCENDING| I2_VPOP | 1 | 00:00:01 | -------------------------------------------------------------------- Statistics 9 consistent gets
  • 33. Pagination SELECT * FROM ( SELECT * FROM ( SELECT name, population SELECT * FROM ( FROM cities SELECT name, population, WHERE state='Florida' rownum AS rn ORDER BY population DESC FROM cities ) WHERE rownum <= 10; WHERE state='Florida' ORDER BY population DESC ) WHERE rownum <= 20 ) WHERE rn > 10;
  • 34. Dumb Pagination ) WHERE rownum <= 20 Statistics ) WHERE rn > 10; 22 consistent gets ) WHERE rownum <= 30 Statistics ) WHERE rn > 20; 32 consistent gets
  • 35. Smart pagination SELECT * FROM ( SELECT * FROM ( SELECT * FROM ( SELECT name, population SELECT name, population, FROM cities rownum AS rn WHERE state='Florida' FROM cities AND population < 154750 WHERE state='Florida' ORDER BY population DESC ORDER BY population DESC ) WHERE rownum <= 10; ) WHERE rownum <= 20 ) WHERE rn > 10; Statistics Statistics 22 consistent gets 12 consistent gets
  • 36. Top-N with joins: Rules • ORDER BY only the LEADING table • Use NESTED LOOPS • Build indexes for STREAMING
  • 37. Top-N with joins SELECT * FROM ( Driving Filter state table: SELECT c.name as city, Order By population c.population, s.capital Join state_id FROM cities c, states s Select name WHERE c.state_id = s.id AND c.state='Florida' ORDER BY c.population DESC Joined to Join id ) WHERE rownum <= 5 table: Select capital /
  • 38. Top-N with joins: Good ------------------------------------------------------- | Id | Operation | Name | Rows | Time | ------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 00:00:13 | |* 1 | COUNT STOPKEY | | | | | 2 | VIEW | | 10 | 00:00:13 | | 3 | NESTED LOOPS | | 10 | 00:00:13 | |* 4 | INDEX RANGE SCAN| I_C | 506 | 00:00:07 | |* 5 | INDEX RANGE SCAN| I_S | 1 | 00:00:01 | -------------------------------------------------------
  • 39. Top-N with joins: Bad ----------------------------------------------------------- | Id | Operation | Name | Rows | Time | ----------------------------------------------------------- | 0 | SELECT STATEMENT | | 5 | 00:00:07 | |* 1 | COUNT STOPKEY | | | | | 2 | VIEW | | 10 | 00:00:07 | |* 3 | SORT ORDER BY STOPKEY| | 10 | 00:00:07 | |* 4 | HASH JOIN | | 10 | 00:00:07 | |* 5 | INDEX RANGE SCAN | I_C | 506 | 00:00:07 | |* 6 | INDEX RANGE SCAN | I_S | 1 | 00:00:01 | -----------------------------------------------------------
  • 40. Gotchas? TMI “Too many indexes”

Notas del editor

  1. This feels a bit 1990s … Let’s see some examples that are more 21st century
  2. Nowadays every website has a search buttonUsers can search for anythingWhen you search you get some results, but these are normally hugeYou need to cut the results and display a few that are most interesting and fit the page (aka: top-n) and then you need to be able to move on to less interesting results (aka: paginate)“Most interesting” can be defined several different ways
  3. Notice no SORT step
  4. Likely: return a few rows, ‘freeze’, then return a few rows again etcFiltering in “plain English”: reading junk
  5. Notice no TABLE ACCESS BY INDEX ROWID – all data is in the index
  6. For pagination, equality filter and order by conditions are tradeableYou can either “fix” the condition (where a=…) or include it into order by
  7. Can work if number of “filtered” conditions is small
  8. … And then we run a select
  9. Alternatively, statement can extract current version from the index itself:SELECT * FROM ( SELECT name, population FROM cities2 WHERE budget_surplus=&apos;Y&apos; AND version=(SELECT max(version) FROM cities2 WHERE budget_surplus=‘Y’) ORDER BY population DESC) WHERE rownum &lt;= 5;