|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.104 2003/08/04 02:39:57 momjian Exp $ |
| 11 | + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.105 2003/09/02 22:10:16 tgl Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
@@ -189,27 +189,39 @@ _bt_check_unique(Relation rel, BTItem btitem, Relation heapRel,
|
189 | 189 | BlockNumber nblkno;
|
190 | 190 |
|
191 | 191 | /*
|
192 |
| - * make sure the offset points to an actual key before trying to |
193 |
| - * compare it... |
| 192 | + * make sure the offset points to an actual item before trying to |
| 193 | + * examine it... |
194 | 194 | */
|
195 | 195 | if (offset <= maxoff)
|
196 | 196 | {
|
197 |
| - /* |
198 |
| - * _bt_compare returns 0 for (1,NULL) and (1,NULL) - this's |
199 |
| - * how we handling NULLs - and so we must not use _bt_compare |
200 |
| - * in real comparison, but only for ordering/finding items on |
201 |
| - * pages. - vadim 03/24/97 |
202 |
| - */ |
203 |
| - if (!_bt_isequal(itupdesc, page, offset, natts, itup_scankey)) |
204 |
| - break; /* we're past all the equal tuples */ |
205 |
| - |
206 | 197 | curitemid = PageGetItemId(page, offset);
|
207 | 198 |
|
208 | 199 | /*
|
209 |
| - * We can skip the heap fetch if the item is marked killed. |
| 200 | + * We can skip items that are marked killed. |
| 201 | + * |
| 202 | + * Formerly, we applied _bt_isequal() before checking the kill |
| 203 | + * flag, so as to fall out of the item loop as soon as possible. |
| 204 | + * However, in the presence of heavy update activity an index |
| 205 | + * may contain many killed items with the same key; running |
| 206 | + * _bt_isequal() on each killed item gets expensive. Furthermore |
| 207 | + * it is likely that the non-killed version of each key appears |
| 208 | + * first, so that we didn't actually get to exit any sooner anyway. |
| 209 | + * So now we just advance over killed items as quickly as we can. |
| 210 | + * We only apply _bt_isequal() when we get to a non-killed item or |
| 211 | + * the end of the page. |
210 | 212 | */
|
211 | 213 | if (!ItemIdDeleted(curitemid))
|
212 | 214 | {
|
| 215 | + /* |
| 216 | + * _bt_compare returns 0 for (1,NULL) and (1,NULL) - this's |
| 217 | + * how we handling NULLs - and so we must not use _bt_compare |
| 218 | + * in real comparison, but only for ordering/finding items on |
| 219 | + * pages. - vadim 03/24/97 |
| 220 | + */ |
| 221 | + if (!_bt_isequal(itupdesc, page, offset, natts, itup_scankey)) |
| 222 | + break; /* we're past all the equal tuples */ |
| 223 | + |
| 224 | + /* okay, we gotta fetch the heap tuple ... */ |
213 | 225 | cbti = (BTItem) PageGetItem(page, curitemid);
|
214 | 226 | htup.t_self = cbti->bti_itup.t_tid;
|
215 | 227 | if (heap_fetch(heapRel, SnapshotDirty, &htup, &hbuffer,
|
@@ -1547,7 +1559,7 @@ _bt_pgaddtup(Relation rel,
|
1547 | 1559 | * _bt_isequal - used in _bt_doinsert in check for duplicates.
|
1548 | 1560 | *
|
1549 | 1561 | * This is very similar to _bt_compare, except for NULL handling.
|
1550 |
| - * Rule is simple: NOT_NULL not equal NULL, NULL not_equal NULL too. |
| 1562 | + * Rule is simple: NOT_NULL not equal NULL, NULL not equal NULL too. |
1551 | 1563 | */
|
1552 | 1564 | static bool
|
1553 | 1565 | _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
|
@@ -1576,7 +1588,7 @@ _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
|
1576 | 1588 | datum = index_getattr(itup, attno, itupdesc, &isNull);
|
1577 | 1589 |
|
1578 | 1590 | /* NULLs are never equal to anything */
|
1579 |
| - if (entry->sk_flags & SK_ISNULL || isNull) |
| 1591 | + if ((entry->sk_flags & SK_ISNULL) || isNull) |
1580 | 1592 | return false;
|
1581 | 1593 |
|
1582 | 1594 | result = DatumGetInt32(FunctionCall2(&entry->sk_func,
|
|
0 commit comments