Skip to content

Commit 27ef132

Browse files
committed
Doc: add some notes about performance of the List functions.
Per suggestion from Andres Freund. Discussion: https://postgr.es/m/20211104221248.pgo4h6wvnjl6uvkb@alap3.anarazel.de
1 parent 87bb606 commit 27ef132

File tree

1 file changed

+55
-5
lines changed

1 file changed

+55
-5
lines changed

src/backend/nodes/list.c

+55-5
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,9 @@ insert_new_cell(List *list, int pos)
410410
/*
411411
* Insert the given datum at position 'pos' (measured from 0) in the list.
412412
* 'pos' must be valid, ie, 0 <= pos <= list's length.
413+
*
414+
* Note that this takes time proportional to the distance to the end of the
415+
* list, since the following entries must be moved.
413416
*/
414417
List *
415418
list_insert_nth(List *list, int pos, void *datum)
@@ -460,6 +463,9 @@ list_insert_nth_oid(List *list, int pos, Oid datum)
460463
* value, rather than continuing to use the pointer passed as the
461464
* second argument.
462465
*
466+
* Note that this takes time proportional to the length of the list,
467+
* since the existing entries must be moved.
468+
*
463469
* Caution: before Postgres 8.0, the original List was unmodified and
464470
* could be considered to retain its separate identity. This is no longer
465471
* the case.
@@ -525,6 +531,10 @@ lcons_oid(Oid datum, List *list)
525531
* Callers should be sure to use the return value as the new pointer to the
526532
* concatenated list: the 'list1' input pointer may or may not be the same
527533
* as the returned pointer.
534+
*
535+
* Note that this takes at least time proportional to the length of list2.
536+
* It'd typically be the case that we have to enlarge list1's storage,
537+
* probably adding time proportional to the length of list1.
528538
*/
529539
List *
530540
list_concat(List *list1, const List *list2)
@@ -623,6 +633,8 @@ list_truncate(List *list, int new_size)
623633
* Return true iff 'datum' is a member of the list. Equality is
624634
* determined via equal(), so callers should ensure that they pass a
625635
* Node as 'datum'.
636+
*
637+
* This does a simple linear search --- avoid using it on long lists.
626638
*/
627639
bool
628640
list_member(const List *list, const void *datum)
@@ -706,6 +718,9 @@ list_member_oid(const List *list, Oid datum)
706718
* Delete the n'th cell (counting from 0) in list.
707719
*
708720
* The List is pfree'd if this was the last member.
721+
*
722+
* Note that this takes time proportional to the distance to the end of the
723+
* list, since the following entries must be moved.
709724
*/
710725
List *
711726
list_delete_nth_cell(List *list, int n)
@@ -777,6 +792,9 @@ list_delete_nth_cell(List *list, int n)
777792
*
778793
* The List is pfree'd if this was the last member. However, we do not
779794
* touch any data the cell might've been pointing to.
795+
*
796+
* Note that this takes time proportional to the distance to the end of the
797+
* list, since the following entries must be moved.
780798
*/
781799
List *
782800
list_delete_cell(List *list, ListCell *cell)
@@ -787,6 +805,8 @@ list_delete_cell(List *list, ListCell *cell)
787805
/*
788806
* Delete the first cell in list that matches datum, if any.
789807
* Equality is determined via equal().
808+
*
809+
* This does a simple linear search --- avoid using it on long lists.
790810
*/
791811
List *
792812
list_delete(List *list, void *datum)
@@ -870,6 +890,13 @@ list_delete_oid(List *list, Oid datum)
870890
* where the intent is to alter the list rather than just traverse it.
871891
* Beware that the list is modified, whereas the Lisp-y coding leaves
872892
* the original list head intact in case there's another pointer to it.
893+
*
894+
* Note that this takes time proportional to the length of the list,
895+
* since the remaining entries must be moved. Consider reversing the
896+
* list order so that you can use list_delete_last() instead. However,
897+
* if that causes you to replace lappend() with lcons(), you haven't
898+
* improved matters. (In short, you can make an efficient stack from
899+
* a List, but not an efficient FIFO queue.)
873900
*/
874901
List *
875902
list_delete_first(List *list)
@@ -884,9 +911,6 @@ list_delete_first(List *list)
884911

885912
/*
886913
* Delete the last element of the list.
887-
*
888-
* This is the opposite of list_delete_first(), but is noticeably cheaper
889-
* with a long list, since no data need be moved.
890914
*/
891915
List *
892916
list_delete_last(List *list)
@@ -910,6 +934,9 @@ list_delete_last(List *list)
910934
* Delete the first N cells of the list.
911935
*
912936
* The List is pfree'd if the request causes all cells to be deleted.
937+
*
938+
* Note that this takes time proportional to the distance to the end of the
939+
* list, since the following entries must be moved.
913940
*/
914941
List *
915942
list_delete_first_n(List *list, int n)
@@ -989,8 +1016,10 @@ list_delete_first_n(List *list, int n)
9891016
* you probably want to use list_concat_unique() instead to avoid wasting
9901017
* the storage of the old x list.
9911018
*
992-
* This function could probably be implemented a lot faster if it is a
993-
* performance bottleneck.
1019+
* Note that this takes time proportional to the product of the list
1020+
* lengths, so beware of using it on long lists. (We could probably
1021+
* improve that, but really you should be using some other data structure
1022+
* if this'd be a performance bottleneck.)
9941023
*/
9951024
List *
9961025
list_union(const List *list1, const List *list2)
@@ -1094,6 +1123,11 @@ list_union_oid(const List *list1, const List *list2)
10941123
* This variant works on lists of pointers, and determines list
10951124
* membership via equal(). Note that the list1 member will be pointed
10961125
* to in the result.
1126+
*
1127+
* Note that this takes time proportional to the product of the list
1128+
* lengths, so beware of using it on long lists. (We could probably
1129+
* improve that, but really you should be using some other data structure
1130+
* if this'd be a performance bottleneck.)
10971131
*/
10981132
List *
10991133
list_intersection(const List *list1, const List *list2)
@@ -1152,6 +1186,11 @@ list_intersection_int(const List *list1, const List *list2)
11521186
*
11531187
* This variant works on lists of pointers, and determines list
11541188
* membership via equal()
1189+
*
1190+
* Note that this takes time proportional to the product of the list
1191+
* lengths, so beware of using it on long lists. (We could probably
1192+
* improve that, but really you should be using some other data structure
1193+
* if this'd be a performance bottleneck.)
11551194
*/
11561195
List *
11571196
list_difference(const List *list1, const List *list2)
@@ -1256,6 +1295,8 @@ list_difference_oid(const List *list1, const List *list2)
12561295
*
12571296
* Whether an element is already a member of the list is determined
12581297
* via equal().
1298+
*
1299+
* This does a simple linear search --- avoid using it on long lists.
12591300
*/
12601301
List *
12611302
list_append_unique(List *list, void *datum)
@@ -1313,6 +1354,11 @@ list_append_unique_oid(List *list, Oid datum)
13131354
* modified in-place rather than being copied. However, callers of this
13141355
* function may have strict ordering expectations -- i.e. that the relative
13151356
* order of those list2 elements that are not duplicates is preserved.
1357+
*
1358+
* Note that this takes time proportional to the product of the list
1359+
* lengths, so beware of using it on long lists. (We could probably
1360+
* improve that, but really you should be using some other data structure
1361+
* if this'd be a performance bottleneck.)
13161362
*/
13171363
List *
13181364
list_concat_unique(List *list1, const List *list2)
@@ -1401,6 +1447,8 @@ list_concat_unique_oid(List *list1, const List *list2)
14011447
*
14021448
* It is caller's responsibility to have sorted the list to bring duplicates
14031449
* together, perhaps via list_sort(list, list_oid_cmp).
1450+
*
1451+
* Note that this takes time proportional to the length of the list.
14041452
*/
14051453
void
14061454
list_deduplicate_oid(List *list)
@@ -1557,6 +1605,8 @@ list_copy_deep(const List *oldlist)
15571605
*
15581606
* Like qsort(), this provides no guarantees about sort stability
15591607
* for equal keys.
1608+
*
1609+
* This is based on qsort(), so it likewise has O(N log N) runtime.
15601610
*/
15611611
void
15621612
list_sort(List *list, list_sort_comparator cmp)

0 commit comments

Comments
 (0)