Re: Planner performance extremely affected by an hanging transaction (20-30 times)?

Поиск
Список
Период
Сортировка
От Tom Lane
Тема Re: Planner performance extremely affected by an hanging transaction (20-30 times)?
Дата
Msg-id 11927.1384199294@sss.pgh.pa.us
обсуждение исходный текст
Ответ на Re: Planner performance extremely affected by an hanging transaction (20-30 times)?  (Andres Freund <andres@2ndquadrant.com>)
Ответы Re: Planner performance extremely affected by an hanging transaction (20-30 times)?  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-performance
Andres Freund <andres@2ndquadrant.com> writes:
> Also, this really isn't going to fix the issue discussed here - this was
> just about the additional ProcArrayLock contention. I don't think it
> would change anything dramatical in your case.

All of these proposals are pretty scary for back-patching purposes,
anyway.  I think what we should consider doing is just changing
get_actual_variable_range() to use a cheaper snapshot type, as in
the attached patch (which is for 9.3 but applies to 9.2 with slight
offset).  On my machine, this seems to make the pathological behavior
in BR's test case go away just fine.  I'd be interested to hear what
it does in the real-world scenarios being complained of.

            regards, tom lane

diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index d8c1a88..d1b9473 100644
*** a/src/backend/utils/adt/selfuncs.c
--- b/src/backend/utils/adt/selfuncs.c
*************** get_actual_variable_range(PlannerInfo *r
*** 4951,4956 ****
--- 4951,4957 ----
              HeapTuple    tup;
              Datum        values[INDEX_MAX_KEYS];
              bool        isnull[INDEX_MAX_KEYS];
+             SnapshotData SnapshotDirty;

              estate = CreateExecutorState();
              econtext = GetPerTupleExprContext(estate);
*************** get_actual_variable_range(PlannerInfo *r
*** 4973,4978 ****
--- 4974,4980 ----
              slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRel));
              econtext->ecxt_scantuple = slot;
              get_typlenbyval(vardata->atttype, &typLen, &typByVal);
+             InitDirtySnapshot(SnapshotDirty);

              /* set up an IS NOT NULL scan key so that we ignore nulls */
              ScanKeyEntryInitialize(&scankeys[0],
*************** get_actual_variable_range(PlannerInfo *r
*** 4989,4996 ****
              /* If min is requested ... */
              if (min)
              {
!                 index_scan = index_beginscan(heapRel, indexRel, SnapshotNow,
!                                              1, 0);
                  index_rescan(index_scan, scankeys, 1, NULL, 0);

                  /* Fetch first tuple in sortop's direction */
--- 4991,5013 ----
              /* If min is requested ... */
              if (min)
              {
!                 /*
!                  * In principle, we should scan the index with our current
!                  * active snapshot, which is the best approximation we've got
!                  * to what the query will see when executed.  But that won't
!                  * be exact if a new snap is taken before running the query,
!                  * and it can be very expensive if a lot of uncommitted rows
!                  * exist at the end of the index (because we'll laboriously
!                  * fetch each one and reject it).  What seems like a good
!                  * compromise is to use SnapshotDirty.    That will accept
!                  * uncommitted rows, and thus avoid fetching multiple heap
!                  * tuples in this scenario.  On the other hand, it will reject
!                  * known-dead rows, and thus not give a bogus answer when the
!                  * extreme value has been deleted; that case motivates not
!                  * using SnapshotAny here.
!                  */
!                 index_scan = index_beginscan(heapRel, indexRel,
!                                              &SnapshotDirty, 1, 0);
                  index_rescan(index_scan, scankeys, 1, NULL, 0);

                  /* Fetch first tuple in sortop's direction */
*************** get_actual_variable_range(PlannerInfo *r
*** 5021,5028 ****
              /* If max is requested, and we didn't find the index is empty */
              if (max && have_data)
              {
!                 index_scan = index_beginscan(heapRel, indexRel, SnapshotNow,
!                                              1, 0);
                  index_rescan(index_scan, scankeys, 1, NULL, 0);

                  /* Fetch first tuple in reverse direction */
--- 5038,5045 ----
              /* If max is requested, and we didn't find the index is empty */
              if (max && have_data)
              {
!                 index_scan = index_beginscan(heapRel, indexRel,
!                                              &SnapshotDirty, 1, 0);
                  index_rescan(index_scan, scankeys, 1, NULL, 0);

                  /* Fetch first tuple in reverse direction */

В списке pgsql-performance по дате отправления:

Предыдущее
От: "ktm@rice.edu"
Дата:
Сообщение: Re: postgresql recommendation memory
Следующее
От: Sergey Konoplev
Дата:
Сообщение: Re: postgresql recommendation memory