Speicherverbrauch / c't Datenbank-Contest

--==========7992C0C996844430C272==========
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Hi,

leider komme ich erst jetzt zu den Letzten Zügen ;) beim c't
Datenbank-Contest; für die mittelgroße Datenbank dürften auch
Kleinigkeiten im Speicherverbrauch interessant sein, daher frage ich
mich, ob ich die "customers"-Tabelle in zwei aufteile: eine, in die die
Daten geschrieben werden, und eine Login-Tabelle, auf die im sonstigen
verlauf zugegriffen wird.

Die customers-Tabelle hat im Falle der mittelgroßen Datenbank 2
Millionen Zeilen. Beim Login und via Foreign Keys beim Bestellen wird
darauf zugegriffen.

Postgres lädt immer die ganze Zeile, oder wird das spaltenweise =
abgelegt
(und reingeladen)?

Weiß gerade jemand Zahlen, wieviel das hier pro Zeile braucht, wenn in
den Varchar-Feldern zwischen 6 und 20 Bytes stehen? Oder gibt es
vielleicht einen Query über den Systemkatalog, mit dem man den
Speicherverbrauch einer Zeile (oder einer Tabelle) errechnen kann? Ich
bin etwas spät, sonst würde ich es einfach ausprobieren ;)


CREATE TABLE customers
(
customerid SERIAL NOT NULL,
firstname VARCHAR(50) NOT NULL,
lastname VARCHAR(50) NOT NULL,
address1 VARCHAR(50) NOT NULL,
address2 VARCHAR(50),
city VARCHAR(50) NOT NULL,
state VARCHAR(50),
zip INT,
country VARCHAR(50) NOT NULL,
region SMALLINT NOT NULL,
email VARCHAR(50),
phone VARCHAR(50),
creditcardtype INT NOT NULL,
creditcard VARCHAR(50) NOT NULL,
creditcardexpiration VARCHAR(50) NOT NULL,
username VARCHAR(50) NOT NULL,
password VARCHAR(50) NOT NULL,
age SMALLINT,
income INT,
gender VARCHAR(1)
);



Die Alternative wäre wie gesagt, zum Lesen folgende Tabelle zu nehmen
und obige nur beim Einfügen:

CREATE TABLE login AS
SELECT customerid, username, password,
creditcardtype::text || ',' ||
creditcard::text || ',' ||
creditcardexpiration::text
FROM customers;


Und dann das ganze mittels Trigger automatisch bei neuen Usern updaten.


Die Test-Server der c't haben 1 GB RAM.


Ciao
Alvar

--
** Alvar C.H. Freude, http://alvar.a-blast.org/
** http://www.wen-waehlen.de/
** http://odem.org/
**=A0http://www.assoziations-blaster.de/

--==========7992C0C996844430C272==========
Content-Type: application/pgp-signature
Content-Transfer-Encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (Darwin)

iD8DBQFDd1e3OndlH63J86wRAl4YAJ0VUFrorH0mXHTHK1e6JmNMLgdzPwCg yf4b
fXBPb07ejoe94F8d8VPIbYo=
=Eiit
-----END PGP SIGNATURE-----

--==========7992C0C996844430C272==========--
Alvar Freude [ So, 13 November 2005 16:11 ] [ ID #1055587 ]

Re: Speicherverbrauch / c't Datenbank-Contest

--=-=-=
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable

Alvar Freude writes:

> leider komme ich erst jetzt zu den Letzten Zügen ;) beim c't
> Datenbank-Contest; für die mittelgroße Datenbank dürften auch
> Kleinigkeiten im Speicherverbrauch interessant sein, daher frage ich
> mich, ob ich die "customers"-Tabelle in zwei aufteile: eine, in die die
> Daten geschrieben werden, und eine Login-Tabelle, auf die im sonstigen
> verlauf zugegriffen wird.

Aus Sicht des relationalen Entwurfs ein klares "das ist böse", aus
Sicht der Optimierung ein klares "könnte was bringen" :-).

> Die customers-Tabelle hat im Falle der mittelgroßen Datenbank 2
> Millionen Zeilen. Beim Login und via Foreign Keys beim Bestellen wird
> darauf zugegriffen.

Speziell bei foreign Keys spielt die Tupelgröße keine Rolle, da dazu
nur ein Indexzugriff nötig ist, und Indexe getrennt von den Daten und
anderen Indexen gehalten werden.

> Postgres lädt immer die ganze Zeile, oder wird das spaltenweise abgelegt
> (und reingeladen)?

Depends. Bei deiner customers-Tabelle würde ich ersteres sagen;
Getoastete Typen können jedoch auch Out-Of-Band gehalten werden.

> Weiß gerade jemand Zahlen, wieviel das hier pro Zeile braucht, wenn in
> den Varchar-Feldern zwischen 6 und 20 Bytes stehen? Oder gibt es
> vielleicht einen Query über den Systemkatalog, mit dem man den
> Speicherverbrauch einer Zeile (oder einer Tabelle) errechnen kann? Ich
> bin etwas spät, sonst würde ich es einfach ausprobieren ;)

Du kannst Daten oder auch ganze Records durch die passende
length(foo_send()) jagen. Das müßte dann genau dem entsprechen, was
auf der Platte landet minus Seitenheader.

Beispiel:

=2D-8<---------------cut here---------------start------------->8---
scratch=3D# select *, length(record_send(foo)) from foo;
bar | length
=2D-------------------------------------------------+------- -
foo | 15
foo bar | 19
foo bar bazzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz | 60
(3 rows)

scratch=3D#
=2D-8<---------------cut here---------------end--------------->8---

HTH
Andreas

--=-=-=
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQBDd2eALABrNA+MjBsRAvUvAJ99WdgbcsNlsTgxqaZGtJR3EpqQHwCd F1su
RmXB1Dyb438x/qcKxPqWuWE=
=63zC
-----END PGP SIGNATURE-----
--=-=-=--
Andreas Seltenreich [ So, 13 November 2005 17:19 ] [ ID #1055588 ]

Re: Speicherverbrauch / c't Datenbank-Contest

On 13.11.2005, at 16:11 Uhr, Alvar Freude wrote:

> Die customers-Tabelle hat im Falle der mittelgroßen Datenbank 2
> Millionen Zeilen. Beim Login und via Foreign Keys beim Bestellen wird
> darauf zugegriffen.

Von der Performance sollte das eigentlich keinen Unterschied machen.
Es könnte sogar Nachteile im Hinblick auf Caching haben, wenn man das =

aufteilt und beide Tabellen unabhängig voneinander in den Cache
geladen werden und sich dann wechselweise wieder aus dem Cache
hinauskicken.

Weiterhin ist es natürlich "böses Design" - aber das zählt ja nun mal=

nicht immer.

> Postgres lädt immer die ganze Zeile, oder wird das spaltenweise
> abgelegt
> (und reingeladen)?

Meines Wissens werden "pages" geladen - das werden dann wohl zumeist
ganze Abschnitte mehrerer Zeilen sein. Je kürzer die Zeile desto mehr =

paßt in den Cache.

> Weiß gerade jemand Zahlen, wieviel das hier pro Zeile braucht, wenn in
> den Varchar-Feldern zwischen 6 und 20 Bytes stehen?

Wenn ich das richtig in Erinnerung habe - Inhaltslänge + 4 Byte. Ich =

bin nicht sicher, ob es bei PG sowas wie einen "Shared-String-
Storage" gibt, sodaß Strings die mehrfach vorkommen, nur einmal
gespeichert werden (macht z.B. FrontBase). Glaube aber nicht, daß es =

den gibt.

cug
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster
Guido Neitzer [ So, 13 November 2005 17:24 ] [ ID #1055589 ]

Re: Speicherverbrauch / c't

--==========E9D0A68487FEE5EBF169==========
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Hi,

-- Andreas Seltenreich <uwi7 [at] rz.uni-karlsruhe.de> wrote:

> Aus Sicht des relationalen Entwurfs ein klares "das ist böse",

klar ;-)


> aus
> Sicht der Optimierung ein klares "könnte was bringen" :-).

ja, wobei einfach ein Riegel mehr Speicher bei einem echten Projekt
natürlich sinnvoller wäre.


> Speziell bei foreign Keys spielt die Tupelgröße keine Rolle, da =
dazu
> nur ein Indexzugriff nötig ist, und Indexe getrennt von den Daten und
> anderen Indexen gehalten werden.

hmmm, ich dachte Postgres muss wegen MVCC auch immer auf die Daten
zugreifen.


> Du kannst Daten oder auch ganze Records durch die passende
> length(foo_send()) jagen. Das müßte dann genau dem entsprechen, was
> auf der Platte landet minus Seitenheader.
[...]
> scratch=3D# select *, length(record_send(foo)) from foo;

hmmm, das record_send ist mir nicht so ganz klar, was kriegt die Funktion
als Paramater? Zumindest die 8.0 hier auf dem Testsystem kennt die
Funktion nur für bytea ...


Ciao
Alvar

--
** Alvar C.H. Freude, http://alvar.a-blast.org/
** http://www.wen-waehlen.de/
** http://odem.org/
**=A0http://www.assozia
--==========E9D0A68487FEE5EBF169==========
Content-Type: application/pgp-signature
Content-Transfer-Encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (Darwin)

iD8DBQFDd3GkOndlH63J86wRApstAKCm7YkS6HOA1057R9/Ri+F0Y6WgLwCd FhFw
5tUkgRxz3tbR3vpa7sk9XGU=
=K6Kj
-----END PGP SIGNATURE-----

--==========E9D0A68487FEE5EBF169==========--
Alvar Freude [ So, 13 November 2005 18:02 ] [ ID #1055590 ]

Re: Speicherverbrauch / c't

--==========779B0716B1D1141BC81B==========
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Hi,

-- Guido Neitzer <guido [at] objectpark.org> wrote:

> Von der Performance sollte das eigentlich keinen Unterschied machen.
> Es könnte sogar Nachteile im Hinblick auf Caching haben, wenn man das
> aufteilt und beide Tabellen unabhängig voneinander in den Cache
> geladen werden und sich dann wechselweise wieder aus dem Cache
> hinauskicken.

eher nicht, da die anderen Daten gar nicht gebraucht werden. Bei dem Test
-- in Real wäre das natürlich was anderes. ;-)

Aber ich denke, dass der Trick hier auch zu schmutzig ist und
wahrscheinlich reicht es bzgl. Speicher auch so aus.


> Meines Wissens werden "pages" geladen - das werden dann wohl zumeist
> ganze Abschnitte mehrerer Zeilen sein. Je kürzer die Zeile desto mehr
> paßt in den Cache.

stimmt. Wäre auch quatsch, die Spalten einzeln zu speichern, dann
bräuchte man ja mehrere Zugriffe, um eine Zeile zu holen.


Ciao
Alvar

--
** Alvar C.H. Freude, http://alvar.a-blast.org/
** http://www.wen-waehlen.de/
** http://odem.org/
**=A0http://www.assoziations-blaster.de/

--==========779B0716B1D1141BC81B==========
Content-Type: application/pgp-signature
Content-Transfer-Encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (Darwin)

iD8DBQFDd3JDOndlH63J86wRAmHzAJ9kAGriKSS5vVzBRR9AB13FY7ZtrwCg 0gkr
w/B+vsElMEnUnFwn07m6YC0=
=ARzY
-----END PGP SIGNATURE-----

--==========779B0716B1D1141BC81B==========--
Alvar Freude [ So, 13 November 2005 18:05 ] [ ID #1055591 ]

Re: Speicherverbrauch / c't

--=-=-=
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: quoted-printable

Alvar Freude writes:

> -- Andreas Seltenreich <uwi7 [at] rz.uni-karlsruhe.de> wrote:
>
>
>> Speziell bei foreign Keys spielt die Tupelgröße keine Rolle, da dazu
>> nur ein Indexzugriff nötig ist, und Indexe getrennt von den Daten und
>> anderen Indexen gehalten werden.
>
> hmmm, ich dachte Postgres muss wegen MVCC auch immer auf die Daten
> zugreifen.

Ack, da hast du wohl recht. *rotwerd*

>> Du kannst Daten oder auch ganze Records durch die passende
>> length(foo_send()) jagen. Das müßte dann genau dem entsprechen, was
>> auf der Platte landet minus Seitenheader.
> [...]
>> scratch=3D# select *, length(record_send(foo)) from foo;
>
> hmmm, das record_send ist mir nicht so ganz klar, was kriegt die Funktion
> als Paramater?

Einen Record-Typ; Sprich eine Zeile, die dann als Bytevektor geliefert
wird.

> Zumindest die 8.0 hier auf dem Testsystem kennt die
> Funktion nur für bytea ...

Sorry, seit 8.0 hat sich die Signatur geändert; Folgendes scheint mit
8.0.3 zu klappen:

select length(record_send(row(foo), 0::oid)) from foo;

Gruß
Andreas

--=-=-=
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQBDd3n2LABrNA+MjBsRAmRqAJ0R2dB1KxJ9sE2/aOqPmGFIAw6H5ACd GfkH
7blvf0t6/6V6saCBm7wNhxY=
=cW2X
-----END PGP SIGNATURE-----
--=-=-=--
Andreas Seltenreich [ So, 13 November 2005 18:37 ] [ ID #1055592 ]
Datenbanken » gmane.comp.db.postgresql.german » Speicherverbrauch / c't Datenbank-Contest

Vorheriges Thema: PostgreSQL unter Windows mit Active Directory
Nächstes Thema: Erste Hilfe bei Installation und Einrichtung