Ich habe eine PostgreSQL-Tabelle. select *
ist sehr langsam während select id
ist schön und schnell. Ich denke, es kann sein, dass die Größe der Reihe sehr groß ist und der Transport eine Weile dauert, oder es kann ein anderer Faktor sein.
Ich benötige alle Felder (oder fast alle), daher ist die Auswahl einer Teilmenge keine schnelle Lösung. Das Auswählen der gewünschten Felder ist immer noch langsam.
Hier ist mein Tabellenschema ohne die Namen:
integer | not null default nextval('core_page_id_seq'::regclass)
character varying(255) | not null
character varying(64) | not null
text | default '{}'::text
character varying(255) |
integer | not null default 0
text | default '{}'::text
text |
timestamp with time zone |
integer |
timestamp with time zone |
integer |
Die Größe des Textfeldes kann beliebig sein. Trotzdem nicht mehr als ein paar Kilobyte im schlimmsten Fall.
Fragen
- Gibt es irgendetwas, das "verrückt ineffizient" schreit?
- Gibt es eine Möglichkeit, die Seitengröße in der Postgres-Befehlszeile zu messen, um das Debuggen zu erleichtern?
length(*)
anstatt es nur zu tunlength(field)
? Ich weiß, dass Zeichen keine Bytes sind, aber ich brauche nur einen ungefähren Wert.Antworten:
Q2:
way to measure page size
PostgreSQL bietet eine Reihe von Funktionen für die Größe von Datenbankobjekten . Ich habe die interessantesten in dieser Abfrage gepackt und unten einige Statistik-Zugriffsfunktionen hinzugefügt . (Das Zusatzmodul pgstattuple bietet noch weitere nützliche Funktionen.)
Dies wird zeigen, dass verschiedene Methoden zur Messung der "Größe einer Zeile" zu sehr unterschiedlichen Ergebnissen führen. Alles hängt davon ab, was Sie genau messen möchten.
Diese Abfrage erfordert Postgres 9.3 oder höher . Für ältere Versionen siehe unten.
Verwenden eines
VALUES
Ausdrucks in einerLATERAL
Unterabfrage , um zu vermeiden, dass Berechnungen für jede Zeile geschrieben werden.Ersetzen Sie
public.tbl
(zweimal) durch Ihren optionalen schemaqualifizierten Tabellennamen, um eine kompakte Ansicht der gesammelten Statistiken über die Größe Ihrer Zeilen zu erhalten. Sie können dies zur wiederholten Verwendung in eine plpgsql-Funktion einbinden, den Tabellennamen als Parameter übergeben undEXECUTE
...Ergebnis:
Für ältere Versionen (Postgres 9.2 oder älter):
Gleiches Ergebnis.
Q1:
anything inefficient?
Sie können die Spaltenreihenfolge optimieren , um einige Bytes pro Zeile zu sparen, die derzeit für das Ausrichtungs-Padding verschwendet werden:
Dies spart zwischen 8 und 18 Bytes pro Zeile. Ich nenne es "Spalte Tetris" . Einzelheiten:
Beachten Sie auch:
quelle
, unnest(val) / ct
durch, (LEAST(unnest(val), unnest(val) * ct)) / (ct - 1 + sign(ct))
und es wirft nicht. Der Grund dafür ist, dass, wenn dies der Fallct
ist0
,val
ersetzt wird durch0
undct
ersetzt wird durch1
.Eine Annäherung an die Größe einer Zeile, einschließlich des Inhalts von TOAST , lässt sich leicht ermitteln, indem die Länge der TEXT-Darstellung der gesamten Zeile abgefragt wird:
Dies ist eine gute Annäherung an die Anzahl der Bytes, die clientseitig bei der Ausführung abgerufen werden:
... unter der Annahme, dass der Aufrufer der Abfrage Ergebnisse im Textformat anfordert, wie es die meisten Programme tun (binäres Format ist möglich, aber in den meisten Fällen die Mühe nicht wert).
Dieselbe Technik könnte angewendet werden, um die
N
"größten Zeilen im Text" zu lokalisieren vontablename
:quelle
Es gibt ein paar Dinge, die passieren könnten. Im Allgemeinen bezweifle ich, dass die Länge das proximale Problem ist. Ich vermute stattdessen, dass Sie ein Längenproblem haben.
Sie sagen, die Textfelder können bis zu einigen k groß werden. Eine Zeile kann im Hauptspeicher nicht länger als 8 KB sein , und es ist wahrscheinlich, dass Ihre größeren Textfelder GETOASTET wurden oder aus dem Hauptspeicher in einen erweiterten Speicher in separaten Dateien verschoben wurden. Dadurch wird der Hauptspeicher schneller (die Auswahl der ID ist also tatsächlich schneller, weil weniger Plattenseiten zugegriffen werden müssen), aber die Auswahl von * wird langsamer, weil mehr zufällige E / A-Vorgänge ausgeführt werden.
Wenn Ihre gesamte Zeilengröße immer noch deutlich unter 8 KB liegt, können Sie versuchen, die Speichereinstellungen zu ändern. Ich warne Sie jedoch davor, dass beim Einfügen eines übergroßen Attributs in den Hauptspeicher schlimme Dinge passieren können. Berühren Sie dies am besten nicht, wenn dies nicht erforderlich ist, und legen Sie in diesem Fall die entsprechenden Grenzwerte über Check-Einschränkungen fest. Transport ist also wahrscheinlich nicht das einzige. Möglicherweise werden viele, viele Felder sortiert, für die zufällige Lesevorgänge erforderlich sind. Eine große Anzahl zufälliger Lesevorgänge kann auch zu Cache-Fehlern führen, und eine große Menge an erforderlichem Speicher kann erfordern, dass Dinge auf der Festplatte materialisiert werden, und eine große Anzahl breiter Zeilen, falls eine Verknüpfung vorhanden ist (und eine, falls TOAST beteiligt ist), kann kostspieliger sein Verbindungsmuster usw.
Das erste, was ich tun würde, ist die Auswahl weniger Zeilen und sehen, ob das hilft. Wenn das funktioniert, könnten Sie versuchen, dem Server auch mehr RAM hinzuzufügen, aber ich würde anfangen und sehen, wo die Leistung aufgrund von Planänderungen und Cache-Fehlern zuerst nachlässt.
quelle
Verwenden der oben genannten Datenbankobjektgrößenfunktionen :
quelle