Frage

Ich habe einen Tisch items mit folgendem Schema (in postgres v9.3.5):

  Column   | Type   |                         Modifiers                  | Storage  
-----------+--------+----------------------------------------------------+----------
 id        | bigint | not null default nextval('items_id_seq'::regclass) | plain    
 data      | text   | not null                                           | extended 
 object_id | bigint | not null                                           | plain    
Indexes:
    "items_pkey" PRIMARY KEY, btree (id)
    "items_object_id_idx" btree (object_id)
Has OIDs: no

Wenn ich eine Abfrage ausführe, bleibt sie sehr lange hängen:

SELECT * FROM "items" WHERE "object_id" = '123' ORDER BY "id" DESC LIMIT 1;

Nach der VAKUUMANALYSE hat sich die Abfrageausführung stark verbessert, ist aber immer noch nicht perfekt.

# EXPLAIN ANALYZE SELECT * FROM "items" WHERE "object_id" = '123' ORDER BY "id" DESC LIMIT 1;
                                                                            QUERY PLAN                                  
------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.44..1269.14 rows=1 width=63) (actual time=873796.061..873796.061 rows=0 loops=1)
   ->  Index Scan Backward using items_pkey on items  (cost=0.44..1164670.11 rows=918 width=63) (actual time=873796.059..873796.059 rows=0 loops=1)
         Filter: (object_id = 123::bigint)
         Rows Removed by Filter: 27942522
 Total runtime: 873796.113 ms
(5 rows)

Das Seltsame ist, dass wenn ich ausführe

SELECT * FROM "items" WHERE "object_id" = '123' LIMIT 1;

es gibt 0 Zeilen zurück und ich kann es in meinem Code tun, um die Leistung meiner Webanwendung zu optimieren, aber warum kann es von Postgres selbst durchgeführt werden?Ich bin von MySQL zu Postgres gekommen und habe dort noch nie so seltsame Dinge gesehen.

=====

Ich habe festgestellt, dass es einen anderen Abfrageplan, einen anderen Index verwendet, aber warum?

# EXPLAIN ANALYZE SELECT * FROM "items" WHERE "object_id" = '123' LIMIT 1;
                                                                          QUERY PLAN                                    
--------------------------------------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.56..3.34 rows=1 width=63) (actual time=0.014..0.014 rows=0 loops=1)
   ->  Index Scan using items_object_id_operation_idx on items  (cost=0.56..2579.16 rows=929 width=63) (actual time=0.013..0.013 rows=0 loops=1)
         Index Cond: (object_id = 123::bigint)
 Total runtime: 0.029 ms
(4 rows)
War es hilfreich?

Lösung 2

zur Optimierung der Abfrage

generasacodicetagpre.

Ich habe Folgendes getan

generasacodicetagpre.

es half ohne hinzugezeigte Index(object_id asc, id desc), die von @mustaccio vorgeschlagen wird.

generasacodicetagpre.

Andere Tipps

Der Versuch zu erklären, warum zwischen den beiden Abfragen Leistungsunterschiede bestehen.

Dieser hier: SELECT * FROM "items" WHERE "object_id" = '123' LIMIT 1 ist zufrieden mit jeder eine Zeile mit dem passenden object_id, also der Index auf object_id ist eine natürliche Wahl.Die Abfrage erfordert minimale E / A:index-Scan, um den ersten übereinstimmenden Wert plus einen gelesenen Heap zu finden, um die gesamte Zeile abzurufen.

Alternative: SELECT * FROM "items" WHERE "object_id" = '123' ORDER BY "id" DESC LIMIT 1 benötigt aller zeilen mit dem passenden object_id nach einer anderen Spalte sortiert werden, id, dann die Zeile mit dem Maximalwert von id zurückgegeben werden.Wenn Sie den Index auf verwenden würden object_id sie müssten die folgenden Vorgänge ausführen:scannen Sie den Index, um zu finden jeder passenden object_id;holen Sie für jedes Match die aktuelle Zeile;sortieren Sie dann alle abgerufenen Zeilen nach id und gib den mit dem größten zurück id.

Die vom Optimierer gewählte Alternative, vermutlich basierend auf der object_id histogramm, ist:scannen Sie den Index auf id rückwärts, in seiner Gesamtheit;holen Sie für jeden Wert die Zeile und prüfen Sie, ob der Wert von object_id League;geben Sie die erste übereinstimmende Zeile zurück, die das maximal mögliche hat id Wert.Diese Alternative vermeidet das Sortieren der Zeilen, daher denke ich, dass der Optimierer es vorzieht, den Index für zu verwenden object_id.

Das Vorhandensein eines Index auf (object_id asc, id desc) ermöglicht eine weitere Alternative:scannen Sie diesen neuen Index nach dem ersten Eintrag, der mit dem angegebenen übereinstimmt object_id wert, der per Definition die höchste haben wird id Wert;holen Sie eine passende Zeile und kehren Sie zurück.Offensichtlich ist dies der effizienteste Ansatz.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit dba.stackexchange
scroll top