Re: [SQL] How to get last 10 rows in a table on a large database? - Mailing list pgsql-sql

From Oleg Bartunov
Subject Re: [SQL] How to get last 10 rows in a table on a large database?
Date
Msg-id Pine.GSO.3.96.SK.991106220719.3910O-200000@ra
Whole thread Raw
In response to Re: [SQL] How to get last 10 rows in a table on a large database?  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-sql
On Sat, 6 Nov 1999, Tom Lane wrote:

> Date: Sat, 06 Nov 1999 13:12:27 -0500
> From: Tom Lane <tgl@sss.pgh.pa.us>
> To: Alex@Icepick.com
> Cc: pgsql-sql@postgreSQL.org
> Subject: Re: [SQL] How to get last 10 rows in a table on a large database? 
> 
> Alex@Icepick.com (Alex) writes:
> > Does anyone have a good idea to get the last 10 rows from a table? I
> > tried 
> > SELECT * FROM table ORDER BY datetime DESC LIMIT 10
> > But my table has over 1 million rows, so this takes forever.. anyone
> > has a better idea on how to do this? 
> 
> FWIW, that query should work the way you want in 7.0 (assuming you have
> an index on datetime).  6.5.* isn't bright enough to use an index for
> ORDER BY DESC, though.  I think Stoyan's suggestion of declaring a
> cursor is probably the best workaround for now --- or you could consult
> the patches list archives for the patch that will make 6.5 use an index.

I attached patch for 6.5.3 Hiroshi kindly made on my request. 
It applies cleanly and seems works ok.
Oleg




> 
>             regards, tom lane
> 
> ************
> 

_____________________________________________________________
Oleg Bartunov, sci.researcher, hostmaster of AstroNet,
Sternberg Astronomical Institute, Moscow University (Russia)
Internet: oleg@sai.msu.su, http://www.sai.msu.su/~megera/
phone: +007(095)939-16-83, +007(095)939-23-83
*** backend/optimizer/plan/planner.c.org    Mon Aug  2 15:27:02 1999
--- backend/optimizer/plan/planner.c    Wed Nov  3 10:04:41 1999
***************
*** 39,45 **** static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup,                List *groupClause,
AttrNumber*grpColIdx,                Plan *subplan);
 
! static bool need_sortplan(List *sortcls, Plan *plan); static Plan *make_sortplan(List *tlist, List *sortcls, Plan
*plannode); /*****************************************************************************
 
--- 39,45 ---- static Plan *make_groupplan(List *group_tlist, bool tuplePerGroup,                List *groupClause,
AttrNumber*grpColIdx,                Plan *subplan);
 
! static ScanDirection get_dir_to_omit_sortplan(List *sortcls, Plan *plan); static Plan *make_sortplan(List *tlist,
List*sortcls, Plan *plannode);  /*****************************************************************************
 
***************
*** 303,310 ****     }     else     {
!         if (parse->sortClause && need_sortplan(parse->sortClause, result_plan))
!             return (make_sortplan(tlist, parse->sortClause, result_plan));         else             return ((Plan *)
result_plan);    }
 
--- 303,319 ----     }     else     {
!         if (parse->sortClause)
!         {
!             ScanDirection    dir = get_dir_to_omit_sortplan(parse->sortClause, result_plan);
!             if (ScanDirectionIsNoMovement(dir))
!                 return (make_sortplan(tlist, parse->sortClause, result_plan));
!             else
!             { 
!                 ((IndexScan *)result_plan)->indxorderdir = dir;
!                 return ((Plan *) result_plan);
!             }
!         }         else             return ((Plan *) result_plan);     }
***************
*** 822,828 ****   /* ----------
!  * Support function for need_sortplan  * ----------  */ static TargetEntry *
--- 831,837 ----   /* ----------
!  * Support function for get scan direction to omit sortplan  * ----------  */ static TargetEntry *
***************
*** 845,855 ****  * Check if a user requested ORDER BY is already satisfied by  * the choosen index scan.  *
!  * Returns TRUE if sort is required, FALSE if can be omitted.  * ----------  */
! static bool
! need_sortplan(List *sortcls, Plan *plan) {     Relation    indexRel;     IndexScan  *indexScan;
--- 854,866 ----  * Check if a user requested ORDER BY is already satisfied by  * the choosen index scan.  *
!  * Returns the direction of Index scan to omit sort,
!  * if sort is required returns NoMovementScanDirection  
!  *  * ----------  */
! static ScanDirection
! get_dir_to_omit_sortplan(List *sortcls, Plan *plan) {     Relation    indexRel;     IndexScan  *indexScan;
***************
*** 858,870 ****     HeapTuple    htup;     Form_pg_index index_tup;     int            key_no = 0;      /* ----------
   * Must be an IndexScan      * ----------      */     if (nodeTag(plan) != T_IndexScan)
 
!         return TRUE;      indexScan = (IndexScan *) plan; 
--- 869,883 ----     HeapTuple    htup;     Form_pg_index index_tup;     int            key_no = 0;
+     ScanDirection   dir, nodir = NoMovementScanDirection; 
+     dir = nodir;     /* ----------      * Must be an IndexScan      * ----------      */     if (nodeTag(plan) !=
T_IndexScan)
!         return nodir;      indexScan = (IndexScan *) plan; 
***************
*** 873,888 ****      * ----------      */     if (plan->lefttree != NULL)
!         return TRUE;     if (plan->righttree != NULL)
!         return TRUE;      /* ----------      * Must be a single index scan      * ----------      */     if
(length(indexScan->indxid)!= 1)
 
!         return TRUE;      /* ----------      * Indices can only have up to 8 attributes. So an ORDER BY using
--- 886,901 ----      * ----------      */     if (plan->lefttree != NULL)
!         return nodir;     if (plan->righttree != NULL)
!         return nodir;      /* ----------      * Must be a single index scan      * ----------      */     if
(length(indexScan->indxid)!= 1)
 
!         return nodir;      /* ----------      * Indices can only have up to 8 attributes. So an ORDER BY using
***************
*** 890,896 ****      * ----------      */     if (length(sortcls) > 8)
!         return TRUE;      /* ----------      * The choosen Index must be a btree
--- 903,909 ----      * ----------      */     if (length(sortcls) > 8)
!         return nodir;      /* ----------      * The choosen Index must be a btree
***************
*** 902,908 ****     if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0)     {
heap_close(indexRel);
!         return TRUE;     }     heap_close(indexRel); 
--- 915,921 ----     if (strcmp(nameout(&(indexRel->rd_am->amname)), "btree") != 0)     {
heap_close(indexRel);
!         return nodir;     }     heap_close(indexRel); 
***************
*** 937,943 ****              * Could this happen?              * ----------              */
!             return TRUE;         }         if (nodeTag(tle->expr) != T_Var)         {
--- 950,956 ----              * Could this happen?              * ----------              */
!             return nodir;         }         if (nodeTag(tle->expr) != T_Var)         {
***************
*** 946,952 ****              * cannot be the indexed attribute              * ----------              */
!             return TRUE;         }         var = (Var *) (tle->expr); 
--- 959,965 ----              * cannot be the indexed attribute              * ----------              */
!             return nodir;         }         var = (Var *) (tle->expr); 
***************
*** 957,963 ****              * that of the index              * ----------              */
!             return TRUE;         }          if (var->varattno != index_tup->indkey[key_no])
--- 970,976 ----              * that of the index              * ----------              */
!             return nodir;         }          if (var->varattno != index_tup->indkey[key_no])
***************
*** 966,972 ****              * It isn't the indexed attribute.              * ----------              */
!             return TRUE;         }          if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) !=
sortcl->opoid)
--- 979,985 ----              * It isn't the indexed attribute.              * ----------              */
!             return nodir;         }          if (oprid(oper("<", resdom->restype, resdom->restype, FALSE)) !=
sortcl->opoid)
***************
*** 975,981 ****              * Sort order isn't in ascending order.              * ----------              */
!             return TRUE;         }          key_no++;
--- 988,1006 ----              * Sort order isn't in ascending order.              * ----------              */
!             if (ScanDirectionIsForward(dir))
!                 return nodir;
!             dir = BackwardScanDirection;
!         }
!         else
!         {
!             /* ----------
!              * Sort order is in ascending order.
!              * ----------
!             */
!             if (ScanDirectionIsBackward(dir))
!                 return nodir;
!             dir = ForwardScanDirection;         }          key_no++;
***************
*** 985,989 ****      * Index matches ORDER BY - sort not required      * ----------      */
!     return FALSE; }
--- 1010,1014 ----      * Index matches ORDER BY - sort not required      * ----------      */
!     return dir; }
*** backend/executor/nodeIndexscan.c.org    Wed May 26 01:08:43 1999
--- backend/executor/nodeIndexscan.c    Wed Nov  3 10:04:41 1999
***************
*** 105,110 ****
--- 105,117 ----      */     estate = node->scan.plan.state;     direction = estate->es_direction;
+     if (ScanDirectionIsBackward(node->indxorderdir))
+     {
+         if (ScanDirectionIsForward(direction))
+             direction = BackwardScanDirection;
+         else if (ScanDirectionIsBackward(direction))
+             direction = ForwardScanDirection;
+     }       snapshot = estate->es_snapshot;     scanstate = node->scan.scanstate;     indexstate = node->indxstate;
***************
*** 322,327 ****
--- 329,336 ----     indxqual = node->indxqual;     numScanKeys = indexstate->iss_NumScanKeys;
indexstate->iss_IndexPtr= -1;
 
+     if (ScanDirectionIsBackward(node->indxorderdir))
+         indexstate->iss_IndexPtr = numIndices;      /* If this is re-scanning of PlanQual ... */     if
(estate->es_evTuple!= NULL &&
 
***************
*** 972,977 ****
--- 981,988 ----     }      indexstate->iss_NumIndices = numIndices;
+     if (ScanDirectionIsBackward(node->indxorderdir))
+         indexPtr = numIndices;     indexstate->iss_IndexPtr = indexPtr;     indexstate->iss_ScanKeys = scanKeys;
indexstate->iss_NumScanKeys= numScanKeys;
 
*** backend/optimizer/plan/createplan.c.org    Thu Jul 29 12:34:11 1999
--- backend/optimizer/plan/createplan.c    Wed Nov  3 10:04:41 1999
***************
*** 1040,1045 ****
--- 1040,1046 ----     node->indxid = indxid;     node->indxqual = indxqual;     node->indxqualorig = indxqualorig;
+     node->indxorderdir = NoMovementScanDirection;     node->scan.scanstate = (CommonScanState *) NULL;      return
node;
*** backend/nodes/copyfuncs.c.org    Wed May 26 07:41:11 1999
--- backend/nodes/copyfuncs.c    Wed Nov  3 10:04:41 1999
***************
*** 251,256 ****
--- 251,257 ----     newnode->indxid = listCopy(from->indxid);     Node_Copy(from, newnode, indxqual);
Node_Copy(from,newnode, indxqualorig);
 
+     newnode->indxorderdir = from->indxorderdir;      return newnode; }
*** backend/nodes/readfuncs.c.org    Wed May 26 01:09:11 1999
--- backend/nodes/readfuncs.c    Wed Nov  3 10:04:41 1999
***************
*** 546,551 ****
--- 546,556 ----     token = lsptok(NULL, &length);        /* eat :indxqualorig */     local_node->indxqualorig =
nodeRead(true);   /* now read it */ 
 
+     token = lsptok(NULL, &length);        /* eat :indxorderdir */
+     token = lsptok(NULL, &length);        /* get indxorderdir */
+ 
+     local_node->indxorderdir = atoi(token);
+      return local_node; } 
*** backend/nodes/outfuncs.c.org    Wed May 26 07:41:14 1999
--- backend/nodes/outfuncs.c    Wed Nov  3 10:04:41 1999
***************
*** 450,455 ****
--- 450,456 ----     appendStringInfo(str, " :indxqualorig ");     _outNode(str, node->indxqualorig); 
+     appendStringInfo(str, " :indxorderdir %d ", node->indxorderdir); }  /*
*** backend/nodes/equalfuncs.c.org    Thu Jul 29 12:34:11 1999
--- backend/nodes/equalfuncs.c    Wed Nov  3 10:04:41 1999
***************
*** 527,532 ****
--- 527,535 ----     if (a->scan.scanrelid != b->scan.scanrelid)         return false; 
+     if (a->indxorderdir != b->indxorderdir)
+         return false;
+      if (!equali(a->indxid, b->indxid))         return false;     return true;
*** backend/commands/explain.c.org    Mon Aug  2 14:56:58 1999
--- backend/commands/explain.c    Wed Nov  3 10:04:41 1999
***************
*** 200,205 ****
--- 200,207 ----     switch (nodeTag(plan))     {         case T_IndexScan:
+             if (ScanDirectionIsBackward(((IndexScan *)plan)->indxorderdir))
+                 appendStringInfo(str, " Backward");             appendStringInfo(str, " using ");             i = 0;
          foreach(l, ((IndexScan *) plan)->indxid)
 
*** include/nodes/plannodes.h.org    Wed May 26 07:42:58 1999
--- include/nodes/plannodes.h    Wed Nov  3 10:04:41 1999
***************
*** 175,180 ****
--- 175,181 ----     List       *indxid;     List       *indxqual;     List       *indxqualorig;
+     ScanDirection    indxorderdir;     IndexScanState *indxstate; } IndexScan; 


pgsql-sql by date:

Previous
From: Tom Lane
Date:
Subject: Re: [SQL] How to get last 10 rows in a table on a large database?
Next
From: Stoyan Genov
Date:
Subject: Move forward all (Was Re: How to get last 10 rows in a table on a large database?)