Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Ja/Nein-Parameter perform speichern

11 views
Skip to first unread message

Georgios Lamark

unread,
Jan 20, 2013, 12:41:58 PM1/20/13
to
Hallo,
ich hᅵtte noch eine Designfrage:
wenn man eine Reihe Ja/Nein-Parameter (>50) speichert (z.B. geschliffen,
gestrahlt, ...), macht man das besser in einzelnen Feldern ᅵ la 0/1 oder
ᅵber ein varchar, in dem IDs (-1-2- ...) auf eine Parameter-Tabelle mit
den Begriffen weisen.
Was ist die performere Lᅵsung? Habt ihr da Erfahrungen? Gibts noch
andere Mᅵglichkeiten?
Gruᅵ, Georgios

Sergej Knjazkow

unread,
Feb 3, 2013, 1:55:16 PM2/3/13
to
Hallo Georgios,

im Bezug auf Query-Performance soll man sich immer eine Frage stellen:
"Welcher Datentyp wird von CPU schneller verarbeitet?"

Grundsᅵtzlich soll man diese Datentypenrangfolge beachten:
bit -> kann direkt von CPU verarbeitet werden
int -> Zahl ist schneller als Text in Computercode ᅵbersetzt
char -> Hat feste Lᅵnge und somit ist schneller als varchar
varchar -> nah ja, ein Text mit variable Lᅵnge
NULL -> fᅵr gute Performance soll man vermeiden

Aus Erfahrung...
Fᅵr 10 Datensetzen in einer Tabelle gibt es fast keinen Unterschied,
aber wenn es ᅵber 1 Mio. Datensetzen bzw. die Datenmenge im
Terabyte-Bereich liegt, dann merkt man schon; Paar Stunden vs. Paar
Tagen ;-)

Als Tipp: Du kannst eine einziger Spalte mit bigint (64bit) Datentype
anlegen und dorthin die Zweierpotenz abspeichern. Somit kannst Du in der
WEHRE-Klausel den "&" Bit-Operator verwenden.
http://dev.mysql.com/doc/refman/5.6/en/bit-functions.html

Somit wird die Tabelle etwas kleiner....

MFG
Sergej

Thomas 'PointedEars' Lahn

unread,
Feb 3, 2013, 5:19:19 PM2/3/13
to
Sergej Knjazkow wrote:

> Am 20.01.2013 18:41, schrieb Georgios Lamark:
>> ich hätte noch eine Designfrage:
>> wenn man eine Reihe Ja/Nein-Parameter (>50) speichert (z.B. geschliffen,
>> gestrahlt, ...), macht man das besser in einzelnen Feldern á la 0/1 oder
>> über ein varchar, in dem IDs (-1-2- ...) auf eine Parameter-Tabelle mit
>> den Begriffen weisen.
>> Was ist die performere Lösung? Habt ihr da Erfahrungen? Gibts noch
>> andere Möglichkeiten?
>
> im Bezug auf Query-Performance soll man sich immer eine Frage stellen:
> "Welcher Datentyp wird von CPU schneller verarbeitet?"

Die CPU dürfte hier zweitrangig sein. Entscheidend ist die
Verarbeitungsgeschwindigkeit eines Datums mit der Datenbank-Engine.
Dort spielt auch die Indizierbarkeit eines Datums hinein.

> Grundsätzlich soll man diese Datentypenrangfolge beachten:
> bit -> kann direkt von CPU verarbeitet werden
> int -> Zahl ist schneller als Text in Computercode übersetzt

Wie kommst Du auf dies schmale Brett?

> char -> Hat feste Länge und somit ist schneller als varchar

Unfug: <http://dev.mysql.com/doc/refman/5.5/en/char.html>

> varchar -> nah ja, ein Text mit variable Länge

Mit variabler, aber maximaler Länge (ibid.).

> NULL -> für gute Performance soll man vermeiden

Unfug. NULL ist kein Datentyp, sondern ein Wert, den jedes Feld annehmen
kann, dessen Spalte nicht explizit das Attribut NOT NULL hat:

<http://dev.mysql.com/doc/refman/5.5/en/working-with-null.html>

> Als Tipp: Du kannst eine einziger Spalte mit bigint (64bit) Datentype
> anlegen und dorthin die Zweierpotenz abspeichern. Somit kannst Du in der
> WEHRE-Klausel den "&" Bit-Operator verwenden.
> http://dev.mysql.com/doc/refman/5.6/en/bit-functions.html

MySQL 5.6 ist derzeit noch nicht stabil, d. h. nicht für den produktiven
Einsatz geeignet. Die Binärfunktionen gibt es jedoch schon in Version 5.5:

<http://dev.mysql.com/doc/refman/5.5/en/bit-functions.html>

> Somit wird die Tabelle etwas kleiner....

8 Bytes je Zeile und Feld sind 8 Bytes je Zeile und Feld. In einer
Datenbank mit 102'400 Zeilen also 8 KiB je BIGINT-Feld. Bei 50 BIGINT-
Feldern also 400 KiB.

Wenn Du genau liest, wirst Du bemerken, dass BIGINT nicht Voraussetzung für
die Verwendung der Binärfunktionen ist, sondern lediglich intern verwendet
wird und somit das *Ergebnis* dieser Funktionen diesen Typ hat:

$ mysql -u root -p tmp -e 'CREATE TEMPORARY TABLE tmp2 SELECT 2 | 3; EXPLAIN
tmp2'
Enter password:
+-------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+-------+
| 2 | 3 | bigint(21) unsigned | NO | | 0 | |
+-------+---------------------+------+-----+---------+-------+

Alle MySQL-Datenbanken, die ich bisher gesehen und erstellt habe, verwenden
für diesen Fall mehrere Felder; das kommt IMHO der Indizierbarkeit zugute
und beschleunigt Abfragen in zweifacher Hinsicht (Verwendung des Index und
Vermeidung von Binäroperationen in der Abfrage).

Es wäre zu überlegen, ob man dann statt UNSIGNED TINYINT den anscheinend
sparsameren Typ BIT(1) wählt; bisher genügte mir ersteres und dieser ist
auch flexibler, wenn man später über Binärlogik hinaus gehen möchte (was mir
regelmässig passiert ist).

<http://dev.mysql.com/doc/refman/5.5/en/integer-types.html>
<http://dev.mysql.com/doc/refman/5.5/en/bit-type.html>

Als Vorbild könnte hier auch MySQL selbst dienen:

$ mysql -u root -p mysql -e 'EXPLAIN user'
Enter password:
+------------------------+-----------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key |
Default | Extra |
+------------------------+-----------------------------------+------+-----+---------+-------+
| Host | char(60) | NO | PRI |
| |
| User | char(16) | NO | PRI |
| |
| Password | char(41) | NO | |
| |
| Select_priv | enum('N','Y') | NO | |
N | |
| Insert_priv | enum('N','Y') | NO | |
N | |
| […]

Wie man sieht, werden dort mehrere Felder und für jedes Ja/Nein-Feld der Typ
ENUM('N', 'Y') verwendet. Man könnte deshalb annehmen, dies sei die
effizienteste Lösung. Ich weiss es nicht.

--
PointedEars

Twitter: @PointedEars2
Please do not Cc: me. / Bitte keine Kopien per E-Mail.

Peter J. Holzer

unread,
Feb 10, 2013, 6:09:56 AM2/10/13
to
On 2013-02-03 18:55, Sergej Knjazkow <serg...@gmx.de> wrote:
> Am 20.01.2013 18:41, schrieb Georgios Lamark:
>> ich hätte noch eine Designfrage:
>> wenn man eine Reihe Ja/Nein-Parameter (>50) speichert (z.B. geschliffen,
>> gestrahlt, ...), macht man das besser in einzelnen Feldern á la 0/1 oder
>> über ein varchar, in dem IDs (-1-2- ...) auf eine Parameter-Tabelle mit
>> den Begriffen weisen.
>> Was ist die performere Lösung? Habt ihr da Erfahrungen? Gibts noch
>> andere Möglichkeiten?
>> Gruß, Georgios
>
> Hallo Georgios,
>
> im Bezug auf Query-Performance soll man sich immer eine Frage stellen:
> "Welcher Datentyp wird von CPU schneller verarbeitet?"

Kaum. Viel mehr sollte man sich die Frage stellen: Welchen Query-Plan
kann der Optimizer aus meiner Query machen?


> Grundsätzlich soll man diese Datentypenrangfolge beachten:
> bit -> kann direkt von CPU verarbeitet werden
> int -> Zahl ist schneller als Text in Computercode übersetzt
> char -> Hat feste Länge und somit ist schneller als varchar
> varchar -> nah ja, ein Text mit variable Länge
> NULL -> für gute Performance soll man vermeiden

Letzteres klingt Oracle-spezifisch. Oracle erzeugt keine Index-Einträge
für NULL-Values, daher ist ein „select ... where x is null“ meist
deutlich langsamer als ein „select ... where x=0“. Das Problem hat MySQL
allerdings nicht. (In Oracle kann man es durch Verwendung von
Bitmap-Indizes oder function-based Indizes umgehen)


> Aus Erfahrung...
> Für 10 Datensetzen in einer Tabelle gibt es fast keinen Unterschied,
> aber wenn es über 1 Mio. Datensetzen bzw. die Datenmenge im
> Terabyte-Bereich liegt, dann merkt man schon; Paar Stunden vs. Paar
> Tagen ;-)
>
> Als Tipp: Du kannst eine einziger Spalte mit bigint (64bit) Datentype
> anlegen und dorthin die Zweierpotenz abspeichern. Somit kannst Du in der
> WEHRE-Klausel den "&" Bit-Operator verwenden.
> http://dev.mysql.com/doc/refman/5.6/en/bit-functions.html
>
> Somit wird die Tabelle etwas kleiner....

Allerdings wird eine solche Query keinen Index verwenden können (oder
der Index muss zumindest vollständig gelesen werden), Du verlierst also
ziemlich sicher mehr Performance durch zusätzliche I/O als Du durch den
geringeren Platzbedarf gewinnst.

Ideal dafür wäre ein tinyint-Feld pro Flag mit jeweils einem eigenen
Index. Aber das hängt auch davon ab, wie gut der Optimizer ist und wie
oft in die Tabelle geschrieben wird - es kann sein, dass bei 50+ Indexes
der Schreibzugriff so langsam wird, dass man sich keine Gedanken mehr
über die Lese-Performance machen muss :-(.

Dem OP bleibt eigentlich nur der Rat: Ausprobieren! Und zwar mit echten
Daten und realistischen Queries.

hp


--
_ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
|_|_) | Sysadmin WSR | Man feilt solange an seinen Text um, bis
| | | h...@hjp.at | die Satzbestandteile des Satzes nicht mehr
__/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel

Harald Stowasser

unread,
Feb 20, 2013, 2:50:20 AM2/20/13
to
Am 20.01.2013 18:41, schrieb Georgios Lamark:
Dafᅵr gibt es M:N Beziehungen.

SELECT produkt_id,produkt FROM produkt;
| id| produkt |
| 2 | Fahrrad |
| 3 | Katze |

SELECT parameter_id,parameter FROM parameter;
| 1 | geschliffen |
| 2 | gestrahlt |
| 3 | lackiert |
| 4 | haarig |
| 5 | lenker |

SELECT produkt_id, parameter_id FROM produkt_parameter;
| 1 | 1 |
| 1 | 2 |
| 2 | 5 |
| 2 | 3 |
| 3 | 4 |

Thomas 'PointedEars' Lahn

unread,
Feb 20, 2013, 3:54:06 AM2/20/13
to
Harald Stowasser wrote:

> Am 20.01.2013 18:41, schrieb Georgios Lamark:
>> ich hätte noch eine Designfrage:
>> wenn man eine Reihe Ja/Nein-Parameter (>50) speichert (z.B. geschliffen,
>> gestrahlt, ...), macht man das besser in einzelnen Feldern á la 0/1 oder
>> über ein varchar, in dem IDs (-1-2- ...) auf eine Parameter-Tabelle mit
>> den Begriffen weisen.
>> Was ist die performere Lösung? Habt ihr da Erfahrungen? Gibts noch
>> andere Möglichkeiten?
>
> Dafür gibt es M:N Beziehungen.

Nein, dafür gerade nicht.

> SELECT produkt_id,produkt FROM produkt;
> | id| produkt |
> | 2 | Fahrrad |
> | 3 | Katze |
>
> SELECT parameter_id,parameter FROM parameter;
> | 1 | geschliffen |
> | 2 | gestrahlt |
> | 3 | lackiert |
> | 4 | haarig |
> | 5 | lenker |
>
> SELECT produkt_id, parameter_id FROM produkt_parameter;
> | 1 | 1 |
> | 1 | 2 |
> | 2 | 5 |
> | 2 | 3 |
> | 3 | 4 |

Und jedes Mal JOIN? Diesen Ansatz solltest Du Dir noch mal überlegen.

Bernd Nawothnig

unread,
Feb 20, 2013, 1:17:09 PM2/20/13
to
On 2013-02-20, Thomas 'PointedEars' Lahn wrote:
> Harald Stowasser wrote:
>
>> Am 20.01.2013 18:41, schrieb Georgios Lamark:
>>> ich hätte noch eine Designfrage:
>>> wenn man eine Reihe Ja/Nein-Parameter (>50) speichert (z.B. geschliffen,
>>> gestrahlt, ...), macht man das besser in einzelnen Feldern á la 0/1 oder
>>> über ein varchar, in dem IDs (-1-2- ...) auf eine Parameter-Tabelle mit
>>> den Begriffen weisen.
>>> Was ist die performere Lösung? Habt ihr da Erfahrungen? Gibts noch
>>> andere Möglichkeiten?
>>
>> Dafür gibt es M:N Beziehungen.
>
> Nein, dafür gerade nicht.

Aber genau dafür gibt es sie. Alles andere ist Murks. Wenn man eine
relationale Datenbank verwendet, sollte man auch mit und nicht gegen
dieses Paradigma coden.

Mehrere Eigenschaften in einen String zu vermanschen, verstößt bereits
gegen die erste Normalform.

>> SELECT produkt_id,produkt FROM produkt;
>> | id| produkt |
>> | 2 | Fahrrad |
>> | 3 | Katze |
>>
>> SELECT parameter_id,parameter FROM parameter;
>> | 1 | geschliffen |
>> | 2 | gestrahlt |
>> | 3 | lackiert |
>> | 4 | haarig |
>> | 5 | lenker |
>>
>> SELECT produkt_id, parameter_id FROM produkt_parameter;
>> | 1 | 1 |
>> | 1 | 2 |
>> | 2 | 5 |
>> | 2 | 3 |
>> | 3 | 4 |
>
> Und jedes Mal JOIN? Diesen Ansatz solltest Du Dir noch mal überlegen.

Wozu?

Der Ansatz ist vollkommen korrekt. Eine ganz normale many to many
Beziehung.




Bernd

Claus Reibenstein

unread,
Feb 21, 2013, 6:53:17 AM2/21/13
to
Bernd Nawothnig schrieb:

> On 2013-02-20, Thomas 'PointedEars' Lahn wrote:
>
>> Harald Stowasser wrote:
>>
>>> Am 20.01.2013 18:41, schrieb Georgios Lamark:
>>>
>>>> wenn man eine Reihe Ja/Nein-Parameter (>50) speichert [...]
ᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵ

>>>> Was ist die performere Lᅵsung? [...]
ᅵᅵᅵᅵᅵᅵᅵᅵᅵᅵ

Soll sicher "performantere" heiᅵen.

>>> Dafᅵr gibt es M:N Beziehungen.
>>
>> Nein, dafᅵr gerade nicht.
>
> Aber genau dafᅵr gibt es sie.

Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
verwalten, ohne dass dazu zwei separate Tabellen notwendig wᅵren.

Gruᅵ
Claus

Thomas 'PointedEars' Lahn

unread,
Feb 21, 2013, 3:17:30 PM2/21/13
to
Bernd Nawothnig wrote:

> On 2013-02-20, Thomas 'PointedEars' Lahn wrote:
>> Harald Stowasser wrote:
>>> Am 20.01.2013 18:41, schrieb Georgios Lamark:
>>>> ich hätte noch eine Designfrage:
>>>> wenn man eine Reihe Ja/Nein-Parameter (>50) speichert (z.B.
>>>> geschliffen, gestrahlt, ...), macht man das besser in einzelnen Feldern
>>>> á la 0/1 oder über ein varchar, in dem IDs (-1-2- ...) auf eine
>>>> Parameter-Tabelle mit den Begriffen weisen.
>>>> Was ist die performere Lösung? Habt ihr da Erfahrungen? Gibts noch
>>>> andere Möglichkeiten?
>>>
>>> Dafür gibt es M:N Beziehungen.
>>
>> Nein, dafür gerade nicht.
>
> Aber genau dafür gibt es sie. Alles andere ist Murks. Wenn man eine
> relationale Datenbank verwendet, sollte man auch mit und nicht gegen
> dieses Paradigma coden.

Niemand hat Derartiges vorgeschlagen.

<http://en.wikipedia.org/wiki/Thought-terminating_clich%C3%A9#Thought-
terminating_clich.C3.A9>

> Mehrere Eigenschaften in einen String zu vermanschen, verstößt bereits
> gegen die erste Normalform.

Niemand hat so eine Lösung vorgeschlagen oder gar behauptet, dass das die
optimale Lösung sei.

>>> SELECT produkt_id,produkt FROM produkt;
>>> | id| produkt |
>>> | 2 | Fahrrad |
>>> | 3 | Katze |
>>>
>>> SELECT parameter_id,parameter FROM parameter;
>>> | 1 | geschliffen |
>>> | 2 | gestrahlt |
>>> | 3 | lackiert |
>>> | 4 | haarig |
>>> | 5 | lenker |
>>>
>>> SELECT produkt_id, parameter_id FROM produkt_parameter;
>>> | 1 | 1 |
>>> | 1 | 2 |
>>> | 2 | 5 |
>>> | 2 | 3 |
>>> | 3 | 4 |
>>
>> Und jedes Mal JOIN? Diesen Ansatz solltest Du Dir noch mal überlegen.
>
> Wozu?

Weil der Ansatz nicht das Anfangskriterium erfüllt: performant. Dazu musst
Du Dir nur überlegen, wie die entsprechende Abfrage aussehen würde.

> Der Ansatz ist vollkommen korrekt.

Aber ungeeignet, weil er nicht skaliert.

> Eine ganz normale many to many Beziehung.

Unnötigerweise.

Thomas 'PointedEars' Lahn

unread,
Feb 21, 2013, 3:21:49 PM2/21/13
to
Claus Reibenstein wrote:

> Bernd Nawothnig schrieb:
>> On 2013-02-20, Thomas 'PointedEars' Lahn wrote:
>>> Harald Stowasser wrote:
>>>> Am 20.01.2013 18:41, schrieb Georgios Lamark:
>>>>> wenn man eine Reihe Ja/Nein-Parameter (>50) speichert [...]
> ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
>>>>> Was ist die performere Lösung? [...]
> ¯¯¯¯¯¯¯¯¯¯
> Soll sicher "performantere" heißen.
>
>>>> Dafür gibt es M:N Beziehungen.
>>>
>>> Nein, dafür gerade nicht.
>>
>> Aber genau dafür gibt es sie.
>
> Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
> verwalten, ohne dass dazu zwei separate Tabellen notwendig wären.

Den braucht man noch nicht einmal. Selbst die 64 Felder des OPs skalieren
besser als Bernds Ansatz.

Bernd Nawothnig

unread,
Feb 26, 2013, 10:59:49 PM2/26/13
to
On 2013-02-21, Claus Reibenstein wrote:
>>>> Dafür gibt es M:N Beziehungen.
>>>
>>> Nein, dafür gerade nicht.
>>
>> Aber genau dafür gibt es sie.
>
> Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
> verwalten, ohne dass dazu zwei separate Tabellen notwendig wären.

Und welche Indextypen unterstützt SET?

Kann man damit _effizient_ z.B. bei 1 Million Produkten nur die
herausfischen, die die Eigenschaften 1, 5 und 8 haben?

Mit einer many to many Beziehung geht das, und zwar effizient.

Klar kostet die mehr Speicher als Hobbylösungen, wie man sie im
MySQL-Umfeld leider häufiger antrifft. Aber sie skaliert eben deutlich
besser, was freilich erst bei großen Datenmengen auffällt. Allerdings
gilt auch: wenn die Datenmenge eh klein ist, stört auch die
zusätzliche Tabelle nicht.

Meine Erfahrung mit großen Datenmengen lautet: es ist immer verkehrt,
wegen ein paar Byte gegen gute und richtige Ansätze zu verstoßen, auch
wenn man erstmal mehr Schreibarbeit damit hat. Dieses bisschen mehr
Aufwand lohnt sich eigentlich immer.






Bernd

--
"Premature optimization is the root of all evil" [Donald E. Knuth]

Bernd Nawothnig

unread,
Feb 26, 2013, 10:42:12 PM2/26/13
to
On 2013-02-21, Thomas 'PointedEars' Lahn wrote:
>>>>> wenn man eine Reihe Ja/Nein-Parameter (>50) speichert (z.B.
>>>>> geschliffen, gestrahlt, ...), macht man das besser in einzelnen Feldern
>>>>> á la 0/1 oder über ein varchar, in dem IDs (-1-2- ...) auf eine
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>>>> Parameter-Tabelle mit den Begriffen weisen.


>>>>> Was ist die performere Lösung? Habt ihr da Erfahrungen? Gibts noch
>>>>> andere Möglichkeiten?
>>>>
>>>> Dafür gibt es M:N Beziehungen.
>>>
>>> Nein, dafür gerade nicht.
>>
>> Aber genau dafür gibt es sie. Alles andere ist Murks. Wenn man eine
>> relationale Datenbank verwendet, sollte man auch mit und nicht gegen
>> dieses Paradigma coden.
>
> Niemand hat Derartiges vorgeschlagen.

Liest Du eigentlich noch, was Du quotest?

><http://en.wikipedia.org/wiki/Thought-terminating_clich%C3%A9#Thought-
> terminating_clich.C3.A9>
>
>> Mehrere Eigenschaften in einen String zu vermanschen, verstößt bereits
>> gegen die erste Normalform.
>
> Niemand hat so eine Lösung vorgeschlagen oder gar behauptet, dass das die
> optimale Lösung sei.

Genau das wurde oben vorgeschlagen. Und IDs in einen String à la
'1-2-3' zu kodieren, ist ein klassischer Verstoß gegen die erste
Normalform.

Wie willst Du denn von da auf die Begriffe ohne Zerlegen des Strings
kommen? Wie willst Du statistische Aussagen über die Eigenschaften
(etwa: wie viele Produkte haben Eigenschaft 3?) treffen? Genau, geht
nicht mehr, zumindest nicht mehr performant. Und weil das so ist, gibt
es die Normalformen.

>>>> SELECT produkt_id,produkt FROM produkt;
>>>> | id| produkt |
>>>> | 2 | Fahrrad |
>>>> | 3 | Katze |
>>>>
>>>> SELECT parameter_id,parameter FROM parameter;
>>>> | 1 | geschliffen |
>>>> | 2 | gestrahlt |
>>>> | 3 | lackiert |
>>>> | 4 | haarig |
>>>> | 5 | lenker |
>>>>
>>>> SELECT produkt_id, parameter_id FROM produkt_parameter;
>>>> | 1 | 1 |
>>>> | 1 | 2 |
>>>> | 2 | 5 |
>>>> | 2 | 3 |
>>>> | 3 | 4 |
>>>
>>> Und jedes Mal JOIN? Diesen Ansatz solltest Du Dir noch mal überlegen.
>>
>> Wozu?
>
> Weil der Ansatz nicht das Anfangskriterium erfüllt: performant. Dazu musst
> Du Dir nur überlegen, wie die entsprechende Abfrage aussehen würde.

Die Begriffe stehen eh in einer anderen Tabelle.

>> Der Ansatz ist vollkommen korrekt.
>
> Aber ungeeignet, weil er nicht skaliert.

Selbstverständlich tut er das. Dafür gibt es Indizes. Wenn der Ansatz
nicht skaliert, dann skalierte keine many to many Beziehung, was
natürlich Unfug ist.

Umgekehrt wird aber ein Schuh daraus. Wie willst Du denn mit der
Stringvariante die Anzahl der Produkte mit Eigenschaft 3 effizient
ermitteln? Da musst Du jede Zeile angucken, den String zerlegen und
aufsummieren: O(n) vs. O(log n), wenn die Tabelle produkt_parameter
richtig indiziert ist. Bei der Bastler"lösung" unter Missachtung der
ersten Normalform können Indizes hingegen nicht greifen.

Was skaliert da also besser?

>> Eine ganz normale many to many Beziehung.
>
> Unnötigerweise.

Du müsstest jetzt noch mit dem Fuß aufstampfen und laut schreien:
"Aber ich habe doch Recht!"




Bernd

Thomas 'PointedEars' Lahn

unread,
Feb 27, 2013, 7:36:26 AM2/27/13
to
Bernd Nawothnig wrote:

> On 2013-02-21, Claus Reibenstein wrote:
>>>>> Dafür gibt es M:N Beziehungen.
>>>> Nein, dafür gerade nicht.
>>> Aber genau dafür gibt es sie.
>> Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
>> verwalten, ohne dass dazu zwei separate Tabellen notwendig wären.
>
> Und welche Indextypen unterstützt SET?

RTFM. SET ist ein String-Typ, bei dem die Werte als Zahlen gespeichert
werden. Somit dürften damit nicht nur alle Indextypen möglich sein, die für
String-Typen möglich sind, sondern sogar alle Indextypen, welche die
jeweilige DB-Engine unterstützt.

> Kann man damit _effizient_ z.B. bei 1 Million Produkten nur die
> herausfischen, die die Eigenschaften 1, 5 und 8 haben?

Ja. Mit SET('Y', 'N'):

SELECT `products_id`
FROM `products`
WHERE `property1` = 'Y' AND `property5` = 'Y' AND `property8` = 'Y'

oder mit SET('p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8'):

SELECT `products_id`
FROM `products`
WHERE FIND_IN_SET('p1', `properties`) > 0
AND FIND_IN_SET('p5', `properties`) > 0
AND FIND_IN_SET('p8', `properties`) > 0

bzw.

SELECT `products_id`
FROM `products`
WHERE `properties` LIKE '%p1%'
AND `properties` LIKE '%p5%'
AND `properties` LIKE '%p8%'

wobei bei letzterer Variante auch Infixe berücksichtigt werden (das kann
sowohl positiv als auch negativ sein).

('p1', 'p2' usw. sind hier durch aussagekräftige Werte zu ersetzen, wie
'geschliffen', 'gestrahlt' usw.; die Verwendung englischsprachiger Worte ist
dann empfehlenswert.)

Am effizientesten bei der Abfrage ist hier aber wohl der String-Typ
ENUM('Y', 'N') mit mehreren Feldern, wobei der Index wieder eine Zahl ist.
MySQL verwendet intern (für die in `mysql`.`user` gespeicherten
Berechtigungen) jenen Datentyp so. Die Abfrage ist dann dieselbe wie für
SET('Y', 'N').

> Mit einer many to many Beziehung geht das, und zwar effizient.

Es ist mit Deinem Ansatz eine vergleichsweise komplizierte, notwendigerweise
komplexere und notwendigerweise ineffizientere asemantische Abfrage mit
JOINs nötig, um die Datensätze für Objekte zu liefern, die gleiche
Eigenschaften haben, nämlich (optimiert):

SELECT `p`.`products_id`
FROM `products` AS `p`
LEFT JOIN `properties` AS `prop` USING (`products_id`)
WHERE `prop`.`value` IN (1, 5, 8)

(Soll die Abfrage semantisch sein, wird es *noch* ineffizienter, weil ein
LEFT JOIN mit der Eigenschafts-ID-zu-Eigenschaftsname-Tabelle hinzukommt.)

Dieser Ansatz skaliert _nicht_ gut, der mit SET(…) oder einem Feld je
Eigenschaft jedoch schon. Denn es werden in der Regel mehr Datensätze als
Felder sein.

Der/Dein Ansatz mit Primär- und Fremdschlüsseln lohnt sich dann, wenn
weitere Eigenschaften gespeichert werden sollen. Aus diesem Grund werden
bei vom Benutzer erweiter- und anpassbaren Shopsystemen wie Magento (MySQL-
basiert) aus der komplexen, Primär- und Fremdschlüssel-basierten
grundlegenden Datenbankstruktur für die häufige Benutzung, wie zum Beispiel
für eine Volltextsuche, sogenannte “flat tables” erstellt, welche die
betreffenden Eigenschaften als Werte von atomaren Eigenschaftsfeldern
bereitstellen.

Die Varianten mit SET und mit mehreren Feldern (INT, ENUM, etc.) haben
gegenüber der Primär-Fremdschlüssel-Variante auch einen Nachteil: Soll eine
Eigenschaft hinzugefügt werden und hat die Tabelle bereits viele Datensätze,
kann das Hinzufügen länger dauern, weil dafür die Tabellenstruktur geändert
werden muss. Neben der Anzahl Datensätze ist daher zur Wahl des Ansatzes
auch zu bedenken, wie wahrscheinlich solche Änderungen sind.

> Klar kostet die mehr Speicher als Hobbylösungen, wie man sie im
> MySQL-Umfeld leider häufiger antrifft. Aber sie skaliert eben deutlich
> besser, was freilich erst bei großen Datenmengen auffällt. Allerdings
> gilt auch: wenn die Datenmenge eh klein ist, stört auch die
> zusätzliche Tabelle nicht.
>
> Meine Erfahrung mit großen Datenmengen lautet: es ist immer verkehrt,
> wegen ein paar Byte gegen gute und richtige Ansätze zu verstoßen, auch
> wenn man erstmal mehr Schreibarbeit damit hat. Dieses bisschen mehr
> Aufwand lohnt sich eigentlich immer.

Dein Ansatz ist aber *in diesem Fall* anscheinend (der OP liefert keinen
Kontext) _nicht_ der richtige, denn es ist *in diesem Fall* anscheinend
_nicht_ der beste. Aber wenn man so wie Du nur einen Hammer hat, sieht eben
jedes Problem wie ein Nagel aus.

kopfschüttelnd,

Claus Reibenstein

unread,
Feb 27, 2013, 7:52:49 AM2/27/13
to
Bernd Nawothnig schrieb:

> On 2013-02-21, Claus Reibenstein wrote:
>
>> Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
>> verwalten, ohne dass dazu zwei separate Tabellen notwendig wᅵren.
>
> Und welche Indextypen unterstᅵtzt SET?

Was meinst Du mit "Indextypen"?

SET-Werte werden als Integers gespeichert. Damit sind alle "Indextypen"
mᅵglich, die auch mit jedem anderen Integer-Wert mᅵglich sind.

> Kann man damit _effizient_ z.B. bei 1 Million Produkten nur die
> herausfischen, die die Eigenschaften 1, 5 und 8 haben?

Kannst Du die umgangssprachliche Aussage "1, 5 und 8" aussagenlogisch
prᅵzisieren? Dann solltest Du eigentlich von alleine auf die Lᅵsung kommen.

> Klar kostet die mehr Speicher als Hobbylᅵsungen, wie man sie im

Hobbylᅵsungen, soso ...

Gruᅵ
Claus

Thomas 'PointedEars' Lahn

unread,
Feb 27, 2013, 7:58:57 AM2/27/13
to
Bernd Nawothnig wrote:

> On 2013-02-21, Thomas 'PointedEars' Lahn wrote:
>>>>>> wenn man eine Reihe Ja/Nein-Parameter (>50) speichert (z.B.
>>>>>> geschliffen, gestrahlt, ...), macht man das besser in einzelnen
>>>>>> Feldern á la 0/1 oder über ein varchar, in dem IDs (-1-2- ...) auf
>>>>>> eine
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>>>>> Parameter-Tabelle mit den Begriffen weisen.
>
>>>>>> Was ist die performere Lösung? Habt ihr da Erfahrungen? Gibts noch
>>>>>> andere Möglichkeiten?
>>>>>
>>>>> Dafür gibt es M:N Beziehungen.
>>>>
>>>> Nein, dafür gerade nicht.
>>>
>>> Aber genau dafür gibt es sie. Alles andere ist Murks. Wenn man eine
>>> relationale Datenbank verwendet, sollte man auch mit und nicht gegen
>>> dieses Paradigma coden.
>>
>> Niemand hat Derartiges vorgeschlagen.
>
> Liest Du eigentlich noch, was Du quotest?

Ja. Ich hatte allerdings SET als ENUM gelesen.

>> <http://en.wikipedia.org/wiki/Thought-terminating_clich%C3%A9#Thought-
>> terminating_clich.C3.A9>
>>
>>> Mehrere Eigenschaften in einen String zu vermanschen, verstößt bereits
>>> gegen die erste Normalform.
>>
>> Niemand hat so eine Lösung vorgeschlagen oder gar behauptet, dass das die
>> optimale Lösung sei.
>
> Genau das wurde oben vorgeschlagen.

SET('...') ist _nicht_ dasselbe wie CHAR oder VARCHAR.

> Und IDs in einen String à la '1-2-3' zu kodieren, ist ein klassischer
> Verstoß gegen die erste Normalform.

Nach Deinem eingeschränkten Verständnis vielleicht.

> Wie willst Du denn von da auf die Begriffe ohne Zerlegen des Strings
> kommen? Wie willst Du statistische Aussagen über die Eigenschaften
> (etwa: wie viele Produkte haben Eigenschaft 3?) treffen? Genau, geht
> nicht mehr, zumindest nicht mehr performant. Und weil das so ist, gibt
> es die Normalformen.

Das ist ein Fehlschluss, siehe meine andere Antwort. Normalisierung sorgt
_nicht_ per se für Effizienz; sondern für atomare Daten, damit
Datenintegrität sowie Vermeidung von Redundanz. Tatsächlich gibt es kaum
eine ineffizientere Operation als eine Kreuzabfrage.

>>>>> SELECT produkt_id,produkt FROM produkt;
>>>>> | id| produkt |
>>>>> | 2 | Fahrrad |
>>>>> | 3 | Katze |
>>>>>
>>>>> SELECT parameter_id,parameter FROM parameter;
>>>>> | 1 | geschliffen |
>>>>> | 2 | gestrahlt |
>>>>> | 3 | lackiert |
>>>>> | 4 | haarig |
>>>>> | 5 | lenker |
>>>>>
>>>>> SELECT produkt_id, parameter_id FROM produkt_parameter;
>>>>> | 1 | 1 |
>>>>> | 1 | 2 |
>>>>> | 2 | 5 |
>>>>> | 2 | 3 |
>>>>> | 3 | 4 |
>>>>
>>>> Und jedes Mal JOIN? Diesen Ansatz solltest Du Dir noch mal überlegen.
>>>
>>> Wozu?
>>
>> Weil der Ansatz nicht das Anfangskriterium erfüllt: performant. Dazu
>> musst Du Dir nur überlegen, wie die entsprechende Abfrage aussehen würde.
>
> Die Begriffe stehen eh in einer anderen Tabelle.

Das ist eben bei einem Ansatz mit SET oder mehreren Spalten _nicht_ nötig.

Mir ist natürlich klar, dass man mit SET sich die nicht nötige Verknüpfung
in der Abfrage mindestens teilweise durch ein komplexeres Abfragekriterium
erkauft. Daher war das auch nicht mein Vorschlag, sondern ENUM und einfache
Datentypen; dann liefert der Spaltenname die Semantik, ebenfalls ohne
Kreuzabfrage.

> >> Der Ansatz ist vollkommen korrekt.
> > Aber ungeeignet, weil er nicht skaliert.
>
> Selbstverständlich tut er das. Dafür gibt es Indizes. Wenn der Ansatz
> nicht skaliert, dann skalierte keine many to many Beziehung, was
> natürlich Unfug ist.

Ex falso quodlibet.

> Umgekehrt wird aber ein Schuh daraus. Wie willst Du denn mit der
> Stringvariante die Anzahl der Produkte mit Eigenschaft 3 effizient
> ermitteln?

Siehe andere Antwort.

> Da musst Du jede Zeile angucken, den String zerlegen und
> aufsummieren:

Muss ich nicht.

> O(n) vs. O(log n), wenn die Tabelle produkt_parameter richtig indiziert
> ist. Bei der Bastler"lösung" unter Missachtung der ersten Normalform
> können Indizes hingegen nicht greifen.

Die MySQL-Leute sind nicht so blöd wie Du Dir einbildest annehmen zu dürfen
und haben deshalb mit SET neben einer effizienten Speicherung und
Indexierung auch Funktionen und Operationen für Abfragen mitgeliefert.
(Sicher hätte man dort aber noch mehr tun können, etwa eine INTERSECT-
Funktion. Die muss man sich mit Binäroperationen zumindest in Version 5.5
AFAIK noch selbst basteln.)

> Was skaliert da also besser?

Ex falso quodlibet.

>>> Eine ganz normale many to many Beziehung.
>> Unnötigerweise.
>
> Du müsstest jetzt noch mit dem Fuß aufstampfen und laut schreien:
> "Aber ich habe doch Recht!"

Nein, im Gegensatz zu Dir kenne ich MySQL sehr gut und habe *stichhaltige*
Argumente aus Theorie und Praxis. Wenn Du die nicht anerkennst, ist das
*Dein* Problem.

Bernd Nawothnig

unread,
Feb 27, 2013, 12:59:28 PM2/27/13
to
On 2013-02-27, Thomas 'PointedEars' Lahn wrote:
> Bernd Nawothnig wrote:
>
>> On 2013-02-21, Claus Reibenstein wrote:
>>>>>> Dafür gibt es M:N Beziehungen.
>>>>> Nein, dafür gerade nicht.
>>>> Aber genau dafür gibt es sie.
>>> Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
>>> verwalten, ohne dass dazu zwei separate Tabellen notwendig wären.
>>
>> Und welche Indextypen unterstützt SET?
>
> RTFM. SET ist ein String-Typ, bei dem die Werte als Zahlen gespeichert
> werden. Somit dürften damit nicht nur alle Indextypen möglich sein, die für
> String-Typen möglich sind, sondern sogar alle Indextypen, welche die
> jeweilige DB-Engine unterstützt.

Die nützen nur nichts, wenn Du auf einzelne Bits zugreifen willst, was
man hier aber braucht. Guckst Du etwa hier:

http://forums.mysql.com/read.php?115,125965,126209#msg-126209

Index is hardly usable with SET datatype.

The function FIND_IN_SET() will make the index unusable.

Oder hier:

http://ftp.nchu.edu.tw/MySQL/tech-resources/articles/mysql-set-datatype.html

an INDEX on a set datatype is going to refer to the set as a whole and
^^^
will not be used for searching individual elements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Also genau wie ich bereits vermutete: so ein Index ist wertlos.

>> Kann man damit _effizient_ z.B. bei 1 Million Produkten nur die
>> herausfischen, die die Eigenschaften 1, 5 und 8 haben?
>
> Ja. Mit SET('Y', 'N'):
>
> SELECT `products_id`
> FROM `products`
> WHERE `property1` = 'Y' AND `property5` = 'Y' AND `property8` = 'Y'

So kommst Du an die Werte ran, das hatte niemand bestritten. Aber
effizient ist das mitnichten. Hier greift nämlich kein Index (s.o),
auch wenn er existieren mag.

> oder mit SET('p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8'):
>
> SELECT `products_id`
> FROM `products`
> WHERE FIND_IN_SET('p1', `properties`) > 0
> AND FIND_IN_SET('p5', `properties`) > 0
> AND FIND_IN_SET('p8', `properties`) > 0
>
> bzw.
>
> SELECT `products_id`
> FROM `products`
> WHERE `properties` LIKE '%p1%'
> AND `properties` LIKE '%p5%'
> AND `properties` LIKE '%p8%'
>
> wobei bei letzterer Variante auch Infixe berücksichtigt werden (das kann
> sowohl positiv als auch negativ sein).
>
> ('p1', 'p2' usw. sind hier durch aussagekräftige Werte zu ersetzen, wie
> 'geschliffen', 'gestrahlt' usw.; die Verwendung englischsprachiger Worte ist
> dann empfehlenswert.)

Alles hart kodiert. Was machst Du, wenn Lokalisierung gewünscht ist?
Geht nicht? Sehr professionell, wirklich. Ich bin beeindruckt.

> Am effizientesten bei der Abfrage ist hier aber wohl der String-Typ
> ENUM('Y', 'N') mit mehreren Feldern, wobei der Index wieder eine Zahl ist.
> MySQL verwendet intern (für die in `mysql`.`user` gespeicherten
> Berechtigungen) jenen Datentyp so. Die Abfrage ist dann dieselbe wie für
> SET('Y', 'N').

Wie so ein Index funktioniert, weißt Du anscheinend nicht. Warum nur
wundert mich das nicht mehr?

Wenn das Indizieren komplexer Datentypen so einfach wäre, wie
Spitzohren sich das denken, warum gibt es dann wohl sowas wie GIN oder
GIST, hm?

>> Mit einer many to many Beziehung geht das, und zwar effizient.
>
> Es ist mit Deinem Ansatz eine vergleichsweise komplizierte,
> notwendigerweise komplexere und notwendigerweise ineffizientere
> asemantische Abfrage mit JOINs nötig, um die Datensätze für Objekte zu
> liefern, die gleiche Eigenschaften haben, nämlich (optimiert):

Erstmal geht es um das Filtern, also das Anwenden etwaiger WHERE
Klauseln. Und die sind beim sauberen Ansatz um Größenordnungen(!)
schneller, nämlich O(n) vs. O(log n) bzw. auch O(1), wenn man, was
hier möglich wäre, einen Hashindex wählt.

Und wenn die Datenbank Index-only-Scans unterstützt, kann das pure
Herauslesen der Information noch mal um den Faktor 10-20 mal schneller
sein. Dann wird nämlich nur noch der Index angefasst, falls alle
gewünschten Spalten indiziert sind.

> SELECT `p`.`products_id`
> FROM `products` AS `p`
> LEFT JOIN `properties` AS `prop` USING (`products_id`)
> WHERE `prop`.`value` IN (1, 5, 8)
>
> (Soll die Abfrage semantisch sein, wird es *noch* ineffizienter, weil ein
> LEFT JOIN mit der Eigenschafts-ID-zu-Eigenschaftsname-Tabelle hinzukommt.)

Hängt von der Größe des Ergebnissets ab. Nebenbei enthält Dein SET
ebenfalls keine Beschreibungen.

> Dieser Ansatz skaliert _nicht_ gut, der mit SET(…) oder einem Feld je
> Eigenschaft jedoch schon.

Der SET Ansatz führt zum Tablescan beim Suchen, also worst case, weil
nun mal auf einzelne Bits normale Indizes nicht anwendbar sind (s.o.).
Schlechter geht es also kaum noch. Der many to many Ansatz hingegen
ist perfekt indizierbar, also so indizierbar, dass der Index beim
Suchen auch sinnvoll verwendet werden kann.

> Denn es werden in der Regel mehr Datensätze als Felder sein.
>
> Der/Dein Ansatz mit Primär- und Fremdschlüsseln lohnt sich dann, wenn
> weitere Eigenschaften gespeichert werden sollen.

Was man im Normalfall immer ermöglichen sollte. Das ist eben der
Unterschied zwischen richtigen und Hobbylösungen.

Der Hobbyfrickler kümmert sich nicht um den u.U. erheblichen Aufwand,
den es kosten kann, wenn man ein zu starres und unflexibles Design im
nachhinein (und das ist immer die teuerste aller Möglichkeiten)
ändern muss. Der tanzt lieber frenetisch um jedes Bit, was er meint,
gespart zu haben, ohne nach links oder rechts zu gucken. Dass gerade
Speicherplatz heute der geringste aller Kostenfaktoren ist,
interessiert ihn nicht groß.

> Aus diesem Grund werden bei vom Benutzer erweiter- und anpassbaren
> Shopsystemen wie Magento (MySQL- basiert) aus der komplexen, Primär-
> und Fremdschlüssel-basierten grundlegenden Datenbankstruktur für die
> häufige Benutzung, wie zum Beispiel für eine Volltextsuche, sogenannte
> “flat tables” erstellt, welche die betreffenden Eigenschaften als
> Werte von atomaren Eigenschaftsfeldern bereitstellen.

Genau, atomar ist das Schlüsselwort bei der ersten Normalform. Wer das
nicht beherzigt, hat noch nicht mal die Basics der relationalen
Datenbanken verstanden.

> Die Varianten mit SET und mit mehreren Feldern (INT, ENUM, etc.) haben
> gegenüber der Primär-Fremdschlüssel-Variante auch einen Nachteil: Soll eine
> Eigenschaft hinzugefügt werden und hat die Tabelle bereits viele Datensätze,
> kann das Hinzufügen länger dauern, weil dafür die Tabellenstruktur geändert
> werden muss. Neben der Anzahl Datensätze ist daher zur Wahl des Ansatzes
> auch zu bedenken, wie wahrscheinlich solche Änderungen sind.

Und bei bereits 64 Eigenschaften ist Schluss - alleine sowas
disqualifiert den Ansatz bereits, denn eine saubere many to many
Beziehung, die da vollkommen flexibel und offen ist, ist kaum
aufwendiger zu implementieren.

>> Klar kostet die mehr Speicher als Hobbylösungen, wie man sie im
>> MySQL-Umfeld leider häufiger antrifft. Aber sie skaliert eben deutlich
>> besser, was freilich erst bei großen Datenmengen auffällt. Allerdings
>> gilt auch: wenn die Datenmenge eh klein ist, stört auch die
>> zusätzliche Tabelle nicht.
>>
>> Meine Erfahrung mit großen Datenmengen lautet: es ist immer verkehrt,
>> wegen ein paar Byte gegen gute und richtige Ansätze zu verstoßen, auch
>> wenn man erstmal mehr Schreibarbeit damit hat. Dieses bisschen mehr
>> Aufwand lohnt sich eigentlich immer.
>
> Dein Ansatz ist aber *in diesem Fall* anscheinend (der OP liefert keinen
> Kontext) _nicht_ der richtige, denn es ist *in diesem Fall* anscheinend
> _nicht_ der beste. Aber wenn man so wie Du nur einen Hammer hat, sieht eben
> jedes Problem wie ein Nagel aus.
>
> kopfschüttelnd,

Für Nägel sollte man sinnvollerweise schon einen Hammer und nicht
gänzlich oder weitgehend ungeeignete Werkzeuge verwenden.




Bernd

Bernd Nawothnig

unread,
Feb 27, 2013, 1:16:40 PM2/27/13
to
On 2013-02-27, Claus Reibenstein wrote:
> Bernd Nawothnig schrieb:
>
>> On 2013-02-21, Claus Reibenstein wrote:
>>
>>> Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
>>> verwalten, ohne dass dazu zwei separate Tabellen notwendig wären.
>>
>> Und welche Indextypen unterstützt SET?
>
> Was meinst Du mit "Indextypen"?

Hash, BTree, GIN, GIST ...

Alleine diese Frage sagt eigentlich bereits alles über Dich zu diesem
Thema.

> SET-Werte werden als Integers gespeichert. Damit sind alle "Indextypen"
> möglich, die auch mit jedem anderen Integer-Wert möglich sind.

Und was hat man davon?

Aber gut, wer noch nicht mal die verschiedenen Indextypen kennt, kann
unmöglich wissen, wo und wie eine Datenbank so einen Index dann in
Folge sinnvoll verwenden kann - oder, was hier viel entscheidender
ist: eben prinzipiell _nicht_ verwenden kann (etwa weil die nötige
Ordnungsrelation fehlt oder, wie beim Hash, nicht vom Index
unterstützt werden kann).

Schade eigentlich, denn *so* grottenschlecht wie ihre
Durchschnittsbenutzer ist MySQL gar nicht. Wenn man will, kann man
auch da sauber mit arbeiten.

>> Kann man damit _effizient_ z.B. bei 1 Million Produkten nur die
>> herausfischen, die die Eigenschaften 1, 5 und 8 haben?
>
> Kannst Du die umgangssprachliche Aussage "1, 5 und 8" aussagenlogisch
> präzisieren? Dann solltest Du eigentlich von alleine auf die Lösung kommen.

Dass es _so_ nicht möglich ist, weiß ich, das ist trivial.

Normalformen existieren nicht so ganz ohne Grund ...

>> Klar kostet die mehr Speicher als Hobbylösungen, wie man sie im
>
> Hobbylösungen, soso ...

Und das war noch sehr höflich ausgedrückt.

Aber wir wollen ja freundlich bleiben.




Bernd

Stefan Froehlich

unread,
Feb 27, 2013, 2:08:37 PM2/27/13
to
On Wed, 27 Feb 2013 18:59:28 Bernd Nawothnig wrote:
> Der Hobbyfrickler kümmert sich nicht um den u.U. erheblichen Aufwand, den
> es kosten kann, wenn man ein zu starres und unflexibles Design im
> nachhinein (und das ist immer die teuerste aller Möglichkeiten) ändern
> muss.

Oh. Ich denke, _gerade_ professionelle Software wird haeufig so entwickelt,
weil jeder zusaetzliche Aufwand Geld kostet, welches nicht verrechenbar
ist, waehrend man bei der spaeter notwendigen Erweiterung ganz zwanglos
noch einmal die Hand aufhalten kann.

Das ist allerdings nicht sonderlich datenbankspezifisch :-)

Sservus,
Stefan

--
http://kontaktinser.at/ - die kostenlose Kontaktboerse fuer Oesterreich
Offizieller Erstbesucher(TM) von mmeike

Für Verführer - säuseln mit Stefan!
(Sloganizer)

Claus Reibenstein

unread,
Feb 27, 2013, 2:22:16 PM2/27/13
to
Bernd Nawothnig schrieb:

> On 2013-02-27, Claus Reibenstein wrote:
>
>> Was meinst Du mit "Indextypen"?
>
> Hash, BTree, GIN, GIST ...
>
> Alleine diese Frage sagt eigentlich bereits alles ᅵber Dich zu diesem
> Thema.

Ja, ich hab' Dich auch ganz doll lieb ...

>> Hobbylᅵsungen, soso ...
>
> Und das war noch sehr hᅵflich ausgedrᅵckt.

Fᅵr Deine Verhᅵltnisse mag das sicher stimmen.

> Aber wir wollen ja freundlich bleiben.

s/bleiben/werden/

Gruᅵ
Claus

Bernd Nawothnig

unread,
Feb 27, 2013, 2:32:18 PM2/27/13
to
On 2013-02-27, Stefan Froehlich wrote:
>> Der Hobbyfrickler kümmert sich nicht um den u.U. erheblichen Aufwand, den
>> es kosten kann, wenn man ein zu starres und unflexibles Design im
>> nachhinein (und das ist immer die teuerste aller Möglichkeiten) ändern
>> muss.
>
> Oh. Ich denke, _gerade_ professionelle Software wird haeufig so entwickelt,
> weil jeder zusaetzliche Aufwand Geld kostet, welches nicht verrechenbar
> ist, waehrend man bei der spaeter notwendigen Erweiterung ganz zwanglos
> noch einmal die Hand aufhalten kann.

Hängt davon ab, was nach dem Stand der Technik voraussehbar war oder
ist. Aber alleine auf die Idee zu kommen, ohne vernünftigen Grund
gegen die erste Normalform zu verstoßen und hart 60
Produkteigenschaften zu kodieren, nur um ein paar popelige Bits zu
sparen, ist fernab jeder Realität - zumindest in meinen Augen. Dazu
kommt ja noch die peinliche Unfähigkeit, Performance korrekt
einzuschätzen (etwa, wo ein Index nützt bzw. überhaupt nützen *kann*).
Wer so denkt oder redet, hat weder den nötigen Sachverstand, noch hat
er höchstwahrscheinlich je Kontakt mit realen Kunden gehabt (und wenn
doch, dann tun mir die Kunden leid). Flexibilität und schnelle
Anpassbarkeit ist heutztage eine der wertvollsten Eigenschaften von
Software. Und da wähle ich ganz sicher nicht im ersten Ansatz irgend
ein hart kodiertes und dazu noch vollkommen unnötiges Limit.

Für das, was Du ansprichst, muss man schon eine Monopolstellung haben
- aber die dürften a) die wenigsten hier haben und <censored> finde
ich es b) deswegen aber trotzdem ;-)

> Das ist allerdings nicht sonderlich datenbankspezifisch :-)

Richtig.




Bernd

Bernd Nawothnig

unread,
Feb 28, 2013, 5:39:05 AM2/28/13
to
On 2013-02-21, Thomas 'PointedEars' Lahn wrote:
> Claus Reibenstein wrote:
>
>> Bernd Nawothnig schrieb:
>>> On 2013-02-20, Thomas 'PointedEars' Lahn wrote:
>>>> Harald Stowasser wrote:
>>>>> Am 20.01.2013 18:41, schrieb Georgios Lamark:
>>>>>> wenn man eine Reihe Ja/Nein-Parameter (>50) speichert [...]
>> ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
>>>>>> Was ist die performere Lösung? [...]
>> ¯¯¯¯¯¯¯¯¯¯
>> Soll sicher "performantere" heißen.
>>
>>>>> Dafür gibt es M:N Beziehungen.
>>>>
>>>> Nein, dafür gerade nicht.
>>>
>>> Aber genau dafür gibt es sie.
>>
>> Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
>> verwalten, ohne dass dazu zwei separate Tabellen notwendig wären.

> Den braucht man noch nicht einmal.

Zu meiner Antwort dazu fiel Dir offensichtlich nichts mehr ein. Also
hast Du nicht mal den Anstand zuzugeben, dass Du Dich da mächtig
vergaloppiert hast.

Es zahlt sich nun mal selten aus, gegen Normalisierung zu verstoßen.
Das dauert meistens nicht lange, bevor man dann stolpert und auf der
Nase liegt.

> Selbst die 64 Felder des OPs skalieren besser als Bernds Ansatz.

Das war nicht mein Ansatz, sondern der von Harald. Ich hatte ihm nur
zugestimmt.

Weißt Du eigentlich, was "skalieren" bedeutet? Wenn Du das meinst,
dann erläutere mal dem erstaunten Publikum, was an einer gehashten m:n
Tabelle schlecht skalieren soll. Ich hoffe, Du weißt schon, dass ein
Hash die Komplexität O(1) hat?

Mich dünkt, Du hast Dir nie Gedanken darüber gemacht, was Edgar F.
Codd seinerzeit mit seinem relationalen Datenbankmodell in erster
Linie angestrebt hat. Das war nämlich exakt das, also *garantiert*
hohe Performance auch bei sehr großen Datenmengen.

Und dann soll es keine gute Idee sein, *immer* als erstes diesen
außerordentlich bewährten Ansatz (es gibt weniges, was so gut durch
die Praxis belegbar ist) zu verfolgen, nur weil Hobbyfrickler Spitzohr
das alles nicht verstanden hat?




Bernd

--
no time toulouse

Dieter Nöth

unread,
Feb 28, 2013, 8:12:48 AM2/28/13
to
Bernd Nawothnig wrote:

> Mich dünkt, Du hast Dir nie Gedanken darüber gemacht, was Edgar F.
> Codd seinerzeit mit seinem relationalen Datenbankmodell in erster
> Linie angestrebt hat. Das war nämlich exakt das, also*garantiert*
> hohe Performance auch bei sehr großen Datenmengen.

Da ist mir neu.
Ich dachte, der Hauptpunkt war das Ganze auf eine saubere
mathematisch-logische Grundlage (Normalisierung und Prädikatenlogik)zu
stellen und Strukturänderungen zu vereinfachen.
Schliesslich gab's bei IBM zu der Zeit nur IMS und das hat zwar hohe
Performance, ist aber sehr unflexibel :-)

Und bei richtig großen Datenmengen fängt man gerne wieder an zu
denormalisieren :-)

Dieter


Thomas 'PointedEars' Lahn

unread,
Feb 28, 2013, 8:42:52 AM2/28/13
to
Bernd Nawothnig wrote:

> On 2013-02-27, Thomas 'PointedEars' Lahn wrote:
>> Bernd Nawothnig wrote:
>>> On 2013-02-21, Claus Reibenstein wrote:
>>>>>>> Dafür gibt es M:N Beziehungen.
>>>>>> Nein, dafür gerade nicht.
>>>>> Aber genau dafür gibt es sie.
>>>> Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
>>>> verwalten, ohne dass dazu zwei separate Tabellen notwendig wären.
>>>
>>> Und welche Indextypen unterstützt SET?
>>
>> RTFM. SET ist ein String-Typ, bei dem die Werte als Zahlen gespeichert
>> werden. Somit dürften damit nicht nur alle Indextypen möglich sein, die
>> für String-Typen möglich sind, sondern sogar alle Indextypen, welche die
>> jeweilige DB-Engine unterstützt.
>
> Die nützen nur nichts, wenn Du auf einzelne Bits zugreifen willst, was
> man hier aber braucht. Guckst Du etwa hier:
>
> http://forums.mysql.com/read.php?115,125965,126209#msg-126209
>
> Index is hardly usable with SET datatype.
>
> The function FIND_IN_SET() will make the index unusable.

Nette Behauptung. Weshalb sollte mich die unmassgebliche Meinung des MySQL-
Forum-Nutzers “KimSeong Loh” interessieren, und wo ist der Beleg für die
Behauptung?

> Oder hier:
>
> http://ftp.nchu.edu.tw/MySQL/tech-resources/articles/mysql-set-
datatype.html
>
> an INDEX on a set datatype is going to refer to the set as a whole and
> ^^^
> will not be used for searching individual elements
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
> Also genau wie ich bereits vermutete: so ein Index ist wertlos.

Da hätte ich dann schon gern eine offizielle Aussage, und nicht eine von
einem dubiosen FTP-Server in Fernost, der anscheinend illegal die MySQL-
Website abbildet und per HTTP bereitstellt.

>>> Kann man damit _effizient_ z.B. bei 1 Million Produkten nur die
>>> herausfischen, die die Eigenschaften 1, 5 und 8 haben?
>>
>> Ja. Mit SET('Y', 'N'):
>>
>> SELECT `products_id`
>> FROM `products`
>> WHERE `property1` = 'Y' AND `property5` = 'Y' AND `property8` = 'Y'
>
> So kommst Du an die Werte ran, das hatte niemand bestritten. Aber
> effizient ist das mitnichten. Hier greift nämlich kein Index (s.o),
> auch wenn er existieren mag.

Bullshit. Das ist äquivalent zu

SELECT `products_id`
FROM `products`
WHERE `property1` & 1 AND `property5` & 1 AND `property8` & 1

Selbst wenn es das nicht so wäre, wäre ein String-Index verwendbar.

>> oder mit SET('p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8'):
>>
>> SELECT `products_id`
>> FROM `products`
>> WHERE FIND_IN_SET('p1', `properties`) > 0
>> AND FIND_IN_SET('p5', `properties`) > 0
>> AND FIND_IN_SET('p8', `properties`) > 0
>>
>> bzw.
>>
>> SELECT `products_id`
>> FROM `products`
>> WHERE `properties` LIKE '%p1%'
>> AND `properties` LIKE '%p5%'
>> AND `properties` LIKE '%p8%'
>>
>> wobei bei letzterer Variante auch Infixe berücksichtigt werden (das kann
>> sowohl positiv als auch negativ sein).
>>
>> ('p1', 'p2' usw. sind hier durch aussagekräftige Werte zu ersetzen, wie
>> 'geschliffen', 'gestrahlt' usw.; die Verwendung englischsprachiger Worte
>> ist dann empfehlenswert.)
>
> Alles hart kodiert. Was machst Du, wenn Lokalisierung gewünscht ist?

Lokalisierung von SQL-Code?

> Geht nicht?

Lokalisierung von SQL-Code geht schon, ist aber nicht sinnvoll (schrieb ich
bereits). Du greifst nach Strohhalmen.

> Sehr professionell, wirklich. Ich bin beeindruckt.

Ich nicht.

>> Am effizientesten bei der Abfrage ist hier aber wohl der String-Typ
>> ENUM('Y', 'N') mit mehreren Feldern, wobei der Index wieder eine Zahl
>> ist. MySQL verwendet intern (für die in `mysql`.`user` gespeicherten
>> Berechtigungen) jenen Datentyp so. Die Abfrage ist dann dieselbe wie für
>> SET('Y', 'N').
>
> Wie so ein Index funktioniert, weißt Du anscheinend nicht. Warum nur
> wundert mich das nicht mehr?

Hast Du auch Argumente?

> Wenn das Indizieren komplexer Datentypen so einfach wäre, wie
> Spitzohren sich das denken, warum gibt es dann wohl sowas wie GIN oder
> GIST, hm?

In *MySQL*? Du wähnst Dich anscheinend in einer anderen Newsgroup.

>>> Mit einer many to many Beziehung geht das, und zwar effizient.
>>
>> Es ist mit Deinem Ansatz eine vergleichsweise komplizierte,
>> notwendigerweise komplexere und notwendigerweise ineffizientere
>> asemantische Abfrage mit JOINs nötig, um die Datensätze für Objekte zu
>> liefern, die gleiche Eigenschaften haben, nämlich (optimiert):
>
> Erstmal geht es um das Filtern, also das Anwenden etwaiger WHERE
> Klauseln. Und die sind beim sauberen Ansatz um Größenordnungen(!)
> schneller, nämlich O(n) vs. O(log n) bzw. auch O(1), wenn man, was
> hier möglich wäre, einen Hashindex wählt.

Hashindizes lassen sich in MySQL 5.5 nur mit der MEMORY-Engine nutzen. Wir
reden hier aber im Normalfall von MyISAM oder bei PK/FK-Strukturen mit
Constraints von InnoDb.

> […]
>> SELECT `p`.`products_id`
>> FROM `products` AS `p`
>> LEFT JOIN `properties` AS `prop` USING (`products_id`)
>> WHERE `prop`.`value` IN (1, 5, 8)
>>
>> (Soll die Abfrage semantisch sein, wird es *noch* ineffizienter, weil ein
>> LEFT JOIN mit der Eigenschafts-ID-zu-Eigenschaftsname-Tabelle
>> hinzukommt.)
>
> Hängt von der Größe des Ergebnissets ab. Nebenbei enthält Dein SET
> ebenfalls keine Beschreibungen.

Doch, die Werte beschreiben sich selbst. Und es ist nicht mein SET, das
möchtest Du endlich mal zur Kenntnis nehmen. Ich habe lediglich gezeigt,
weshalb der Vorschlag von anderen durchaus sinnvoll sein kann.

>> Dieser Ansatz skaliert _nicht_ gut, der mit SET(…) oder einem Feld je
>> Eigenschaft jedoch schon.
>
> Der SET Ansatz führt zum Tablescan beim Suchen, also worst case, weil
> nun mal auf einzelne Bits normale Indizes nicht anwendbar sind (s.o.).
> […]

Ex falso quodlibet.

Bernd Nawothnig

unread,
Feb 28, 2013, 10:00:00 AM2/28/13
to
On 2013-02-28, Dieter Nöth wrote:
> Bernd Nawothnig wrote:
>
>> Mich dünkt, Du hast Dir nie Gedanken darüber gemacht, was Edgar F.
>> Codd seinerzeit mit seinem relationalen Datenbankmodell in erster
>> Linie angestrebt hat. Das war nämlich exakt das, also*garantiert*
>> hohe Performance auch bei sehr großen Datenmengen.
>
> Da ist mir neu.
> Ich dachte, der Hauptpunkt war das Ganze auf eine saubere
> mathematisch-logische Grundlage (Normalisierung und Prädikatenlogik)zu
> stellen und Strukturänderungen zu vereinfachen.

Das sicher auch, Codd war schließlich von Haus aus Mathematiker. Aber
er war ebenso interessiert an hoher Performance - sonst hätte sich die
Sache gegen die bereits etablierten Datenbanken niemals durchsetzen
können. Und soweit ich weiß, lässt sich sogar mathematisch zeigen,
dass man das relationale Datenbankmodell effizient implementieren kann
- vermutlich, weil es so bestechend einfach ist.

> Schliesslich gab's bei IBM zu der Zeit nur IMS und das hat zwar hohe
> Performance, ist aber sehr unflexibel :-)

Du hast schon Recht: es ging um die optimale Verbindung, also so
flexibel wie möglich, und trotzdem performant bleiben. Wobei er aber
schon Abstriche in der Flexibilität eben aus Gründen der Performance
gemacht hat, weswegen Rekursion ursprünglich ausdrücklich und
absichtlich nicht vorgesehen ist. Das relationale Datenbankmodell ist
so nicht turing complete. Das ist eben der Preis für die hohe
Leistungsfähigkeit.

> Und bei richtig großen Datenmengen fängt man gerne wieder an zu
> denormalisieren :-)

Das dürfte sehr vom Einzelfall abhängen. Was ich bereits in der
Hinsicht gemacht habe, war die Verwendung von Arrays für Sensordaten,
auf die sich aber an keiner anderen Stelle bezogen wurde und wo dieser
Bezug auch für die Zukunft sicher auszuschließen war. Dann geht das in
Ordnung, dann spart man so nur Speicherplatz. Aber so ein Spezialfall
lag hier nicht vor. Hier wurden Fremdschlüssel in ein SET verwurstet.
Und sowas ist genau so hässlich wie ineffizient. Sowas macht man
einfach nicht, wenn man eine relationale Datenbank verwendet. Das
erinnert eher an BASIC und Homecomputerzeiten. Und wer das nicht
einsehen mag, probiere es aus und wundere sich dann über die
grottenschlechte Performance beim Suchen. Wer Suchen auf einer nicht
indizierbaren, bzw. nicht über irgendeinen der verfügbaren Indextypen
zu beschleunigenden Spalte in Kauf nimmt, hat noch nie mit großen
Datenmengen gearbeitet.

Bernd Nawothnig

unread,
Feb 28, 2013, 10:39:22 AM2/28/13
to
On 2013-02-28, Thomas 'PointedEars' Lahn wrote:
>>>>> Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
>>>>> verwalten, ohne dass dazu zwei separate Tabellen notwendig wären.
>>>>
>>>> Und welche Indextypen unterstützt SET?
>>>
>>> RTFM. SET ist ein String-Typ, bei dem die Werte als Zahlen gespeichert
>>> werden. Somit dürften damit nicht nur alle Indextypen möglich sein, die
>>> für String-Typen möglich sind, sondern sogar alle Indextypen, welche die
>>> jeweilige DB-Engine unterstützt.
>>
>> Die nützen nur nichts, wenn Du auf einzelne Bits zugreifen willst, was
>> man hier aber braucht. Guckst Du etwa hier:
>>
>> http://forums.mysql.com/read.php?115,125965,126209#msg-126209
>>
>> Index is hardly usable with SET datatype.
>>
>> The function FIND_IN_SET() will make the index unusable.
>
> Nette Behauptung. Weshalb sollte mich die unmassgebliche Meinung des MySQL-
> Forum-Nutzers “KimSeong Loh” interessieren, und wo ist der Beleg für die
> Behauptung?

Belegen solltest eher Du deine Behauptung, denn es ist nicht
ersichtlich, wie man einzelne Bits über einen einzigen index über das
gesamte Bitfeld erfassen kann. Wie stellst Du Dir sowas denn vor?
Welche Ordnungsrelation willst Du da verwenden?

Oder meinst Du auch, Du könntest z.B. folgende Abfrage über einen
BTree Index auf Spalte s1 vom Typ varchar beschleunigen:

SELECT s1 FROM t1 WHERE s1 LIKE '%foo%';

?

Da hilft Dir ein Index ebenso wenig wie beim Suchen nach einzelnen
Bits in einem Bitfeld. Und sowas weiß man einfach, wenn man Erfahrung
mit relationalen Datenbanken hat. Ja, wenn man die eben hat. Und dabei
ist es vollkommen egal, um was für eine relationale Datenbank es sich
dabei handelt. Das gilt für MySQL ebenso wie für Oracle, PostgreSQL,
SQLite oder was auch immer.

Gut, wenn da nur der signifikante Unterschied zwischen den zugehörigen
Benutzergruppen nicht wäre. Gewisse Datenbanken scheinen die
versammelte Dummheit und Ignoranz wie ein Magnet anzuziehen. Das ist
MySQL allerdings nicht anzulasten. Für seine Fans kann niemand was.

Aber gut, ein wenig lass ich Dich noch tanzen - zeige mir durch ein
EXPLAIN SELECT, dass bei der Suche nach einzelnen Bits in einem
Bitfeld ein Index wirklich verwendet wird.

Ich bin gespannt!

>> Oder hier:
>>
>> http://ftp.nchu.edu.tw/MySQL/tech-resources/articles/mysql-set-
> datatype.html
>>
>> an INDEX on a set datatype is going to refer to the set as a whole and
>> ^^^
>> will not be used for searching individual elements
>> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>
>> Also genau wie ich bereits vermutete: so ein Index ist wertlos.
>
> Da hätte ich dann schon gern eine offizielle Aussage, und nicht eine von
> einem dubiosen FTP-Server in Fernost, der anscheinend illegal die MySQL-
> Website abbildet und per HTTP bereitstellt.

Deine Nebelkerzen sind mindestens so schlecht wie das, was Du für
Argumente hältst.

Rede nicht, belege Deine Behauptung durch ein EXPLAIN SELECT!

>>>> Kann man damit _effizient_ z.B. bei 1 Million Produkten nur die
>>>> herausfischen, die die Eigenschaften 1, 5 und 8 haben?
>>>
>>> Ja. Mit SET('Y', 'N'):
>>>
>>> SELECT `products_id`
>>> FROM `products`
>>> WHERE `property1` = 'Y' AND `property5` = 'Y' AND `property8` = 'Y'
>>
>> So kommst Du an die Werte ran, das hatte niemand bestritten. Aber
>> effizient ist das mitnichten. Hier greift nämlich kein Index (s.o),
>> auch wenn er existieren mag.
>
> Bullshit. Das ist äquivalent zu
>
> SELECT `products_id`
> FROM `products`
> WHERE `property1` & 1 AND `property5` & 1 AND `property8` & 1
>
> Selbst wenn es das nicht so wäre, wäre ein String-Index verwendbar.

Rede nicht, zeig uns das entsprechende EXPLAIN SELECT!

Es kann gar kein Index bei sowas verwendet werden. Weder bei MySQL
noch sonstwo. Aber dazu müsste man natürlich wissen, was ein B-Baum
ist. Ich vergaß ...

[...]

>>> Am effizientesten bei der Abfrage ist hier aber wohl der String-Typ
>>> ENUM('Y', 'N') mit mehreren Feldern, wobei der Index wieder eine Zahl
>>> ist. MySQL verwendet intern (für die in `mysql`.`user` gespeicherten
>>> Berechtigungen) jenen Datentyp so. Die Abfrage ist dann dieselbe wie für
>>> SET('Y', 'N').
>>
>> Wie so ein Index funktioniert, weißt Du anscheinend nicht. Warum nur
>> wundert mich das nicht mehr?
>
> Hast Du auch Argumente?
>
>> Wenn das Indizieren komplexer Datentypen so einfach wäre, wie
>> Spitzohren sich das denken, warum gibt es dann wohl sowas wie GIN oder
>> GIST, hm?
>
> In *MySQL*? Du wähnst Dich anscheinend in einer anderen Newsgroup.

Die Welt relationaler Datenbanken besteht nicht nur aus MySQL. Ich
wiederhole meine Frage: Wenn das Indizieren komplexer Daten wirklich
so einfach wäre, wie Du Dir das vorstellst, warum gibt es anderswo
überhaupt sowas wie wie R-Tree, GIN oder GIST? Sind die alle blöd?

>>>> Mit einer many to many Beziehung geht das, und zwar effizient.
>>>
>>> Es ist mit Deinem Ansatz eine vergleichsweise komplizierte,
>>> notwendigerweise komplexere und notwendigerweise ineffizientere
>>> asemantische Abfrage mit JOINs nötig, um die Datensätze für Objekte zu
>>> liefern, die gleiche Eigenschaften haben, nämlich (optimiert):
>>
>> Erstmal geht es um das Filtern, also das Anwenden etwaiger WHERE
>> Klauseln. Und die sind beim sauberen Ansatz um Größenordnungen(!)
>> schneller, nämlich O(n) vs. O(log n) bzw. auch O(1), wenn man, was
>> hier möglich wäre, einen Hashindex wählt.
>
> Hashindizes lassen sich in MySQL 5.5 nur mit der MEMORY-Engine nutzen. Wir
> reden hier aber im Normalfall von MyISAM oder bei PK/FK-Strukturen mit
> Constraints von InnoDb.

Selbst O(log n) ist eine ganze Klasse besser als O(n). Und für sehr
große n wird der Unterschied zu O(1) immer geringer. Für die Praxis
kann man das getrost als "fast konstant" annehmen.

Aber gut, dazu müsste man natürlich mal richtig große Datenmengen live
erlebt haben. Ich vergaß ...

>> […]
>>> SELECT `p`.`products_id`
>>> FROM `products` AS `p`
>>> LEFT JOIN `properties` AS `prop` USING (`products_id`)
>>> WHERE `prop`.`value` IN (1, 5, 8)
>>>
>>> (Soll die Abfrage semantisch sein, wird es *noch* ineffizienter, weil ein
>>> LEFT JOIN mit der Eigenschafts-ID-zu-Eigenschaftsname-Tabelle
>>> hinzukommt.)
>>
>> Hängt von der Größe des Ergebnissets ab. Nebenbei enthält Dein SET
>> ebenfalls keine Beschreibungen.
>
> Doch, die Werte beschreiben sich selbst.

Ein Bit beschreibt sich selbst. Spitzohr beschreibt seine kleine
1-Bit-Welt.

Köstlich.

Thomas 'PointedEars' Lahn

unread,
Feb 28, 2013, 11:56:54 AM2/28/13
to
Bernd Nawothnig wrote:

> On 2013-02-28, Thomas 'PointedEars' Lahn wrote:
>>>>>> Du kennst den Datentyp SET? Damit lassen sich bis zu 64 Attribute
>>>>>> verwalten, ohne dass dazu zwei separate Tabellen notwendig wären.
>>>>>
>>>>> Und welche Indextypen unterstützt SET?
>>>>
>>>> RTFM. SET ist ein String-Typ, bei dem die Werte als Zahlen gespeichert
>>>> werden. Somit dürften damit nicht nur alle Indextypen möglich sein,
>>>> die für String-Typen möglich sind, sondern sogar alle Indextypen,
>>>> welche die jeweilige DB-Engine unterstützt.
>>>
>>> Die nützen nur nichts, wenn Du auf einzelne Bits zugreifen willst, was
>>> man hier aber braucht. Guckst Du etwa hier:
>>>
>>> http://forums.mysql.com/read.php?115,125965,126209#msg-126209
>>>
>>> Index is hardly usable with SET datatype.
>>>
>>> The function FIND_IN_SET() will make the index unusable.
>>
>> Nette Behauptung. Weshalb sollte mich die unmassgebliche Meinung des
>> MySQL- Forum-Nutzers “KimSeong Loh” interessieren, und wo ist der Beleg
>> für die Behauptung?
>
> Belegen solltest eher Du deine Behauptung,

Nein, *alle* Behauptungen sollten begründet belegt werden. Insbesondere
solltest Du langsam mal anfangen, nicht-dubiose Belege für Deine
aussergewöhnlichen Behauptungen zu bringen. Aussergewöhnliche Behauptungen
erfordern aussergewöhnliche Belege.

> denn es ist nicht ersichtlich, wie man einzelne Bits über einen einzigen
> index über das gesamte Bitfeld erfassen kann. Wie stellst Du Dir sowas
> denn vor?

Es werden ja gar nicht einzelne Bits oder Bitpositionen gespeichert, sondern
einfach ganzzahlige Werte. Steht also in einem Feld in einer Spalte des
Typs SET('red', 'green', 'blue') für den Benutzer 'red,blue', dann steht
dort für die Engine die Zahl 5 = 2⁰ ('red') + 2² ('blue'). Umgekehrt ist
die Abfrage

SELECT …
FROM …
WHERE `properties` = 'red,blue'

für die Engine offensichtlich (dokumentiert) gleichbedeutend mit

SELECT …
FROM …
WHERE `properties` = 5

Deshalb lassen sich statt (äusserlichen) Stringvergleichen auch
Binäroperationen mit dem Feldwert durchführen, etwa ob der SET-Feldwert
'red' enthält:

SELECT …
FROM …
WHERE `properties` & 4

bzw.

SELECT …
FROM …
WHERE `properties` & 4 > 0

Gleichermassen darf angenommen werden, dass das die Form der Abfrage nach
Optimierung von

SELECT …
FROM …
WHERE FIND_IN_SET('red', `properties`) > 0

durch die Engine ist. Immerhin *muss* die Engine den Wert 'red' zur
entsprechenden Zweierpotenz auflösen, wenn sie ein sinnvolles
Abfrageergebnis liefern soll.

Und es gibt keinen guten Grund, weshalb sich diese ganzzahligen Werte nicht
wie alle anderen Zahlenwerte indizieren lassen sollten.

<http://dev.mysql.com/doc/refman/5.5/en/set.html>

Mein Vorschlag waren allerdings mehrere ENUM-Spalten.

> Aber gut, ein wenig lass ich Dich noch tanzen - […]

Neinnein, *Du* gibst hier weiterhin den Kasper.

>>> […]
>>>> SELECT `p`.`products_id`
>>>> FROM `products` AS `p`
>>>> LEFT JOIN `properties` AS `prop` USING (`products_id`)
>>>> WHERE `prop`.`value` IN (1, 5, 8)
>>>>
>>>> (Soll die Abfrage semantisch sein, wird es *noch* ineffizienter, weil
>>>> ein LEFT JOIN mit der Eigenschafts-ID-zu-Eigenschaftsname-Tabelle
>>>> hinzukommt.)
>>>
>>> Hängt von der Größe des Ergebnissets ab. Nebenbei enthält Dein SET
>>> ebenfalls keine Beschreibungen.
>>
>> Doch, die Werte beschreiben sich selbst.
>
> Ein Bit beschreibt sich selbst.

Ja, gewissermassen. Schliesslich wird ein Element der Menge mit dem
abstrakten Wert einer Zweierpotenz dem Benutzer der Engine als von ihm
definierte (natürlichsprachige) Zeichenfolge präsentiert.

Dieter Nöth

unread,
Feb 28, 2013, 12:12:55 PM2/28/13
to
Thomas 'PointedEars' Lahn wrote:

>>> Ja. Mit SET('Y', 'N'):
>>> >>
>>> >> SELECT `products_id`
>>> >> FROM `products`
>>> >> WHERE `property1` = 'Y' AND `property5` = 'Y' AND `property8` = 'Y'
>> >
>> >So kommst Du an die Werte ran, das hatte niemand bestritten. Aber
>> >effizient ist das mitnichten. Hier greift nämlich kein Index (s.o),
>> >auch wenn er existieren mag.
> Bullshit. Das ist äquivalent zu
>
> SELECT `products_id`
> FROM `products`
> WHERE `property1` & 1 AND `property5` & 1 AND `property8` & 1
>
> Selbst wenn es das nicht so wäre, wäre ein String-Index verwendbar.

Du meinst jetzt tatsächlich einen Index auf einer Spalte mit zwei
Ausprägungen? Ja/Nein, 0/1?
Und auf jeder property-Spalte einen Indes?

Dann müsste aber jedes einzelne property sehr selten sein, damit die
Selektivität stimmt.

Kann mySQL denn ein Bit-Mapping oder ein Intersect von mehreren Indices?

Dieter


Bernd Nawothnig

unread,
Feb 28, 2013, 1:45:10 PM2/28/13
to
On 2013-02-28, Thomas 'PointedEars' Lahn wrote:
>> denn es ist nicht ersichtlich, wie man einzelne Bits über einen einzigen
>> index über das gesamte Bitfeld erfassen kann. Wie stellst Du Dir sowas
>> denn vor?
>
> Es werden ja gar nicht einzelne Bits oder Bitpositionen gespeichert, sondern
> einfach ganzzahlige Werte.

Eben. Und darum werden auch keine einzelnen Bits indiziert, sondern
das gesamte Feld.

> Steht also in einem Feld in einer Spalte des Typs SET('red', 'green',
> 'blue') für den Benutzer 'red,blue', dann steht dort für die Engine
> die Zahl 5 = 2⁰ ('red') + 2² ('blue'). Umgekehrt ist die Abfrage
>
> SELECT …
> FROM …
> WHERE `properties` = 'red,blue'
>
> für die Engine offensichtlich (dokumentiert) gleichbedeutend mit
>
> SELECT …
> FROM …
> WHERE `properties` = 5

Sicher. Und genau deswegen kannst Du blue alleine nicht indizieren.

Wie soll denn da die zugehörige Ordnungsrelation auf der_gesamten_
Spalte aussehen? Ich fragte Dich das schon mal. Weißt Du denn
überhaupt, inwiefern ein B-Baum bei der Suche hilft, bzw. nur helfen
kann? Dazu brauchst zu _zwingend_ eine Ordnungsrelation.

Einzig das MS-Bit könntest Du mit sowas noch alleine greifen, mehr
aber nicht (denn b'1xxxxxx' ist unsigned größer als '0xxxxxxx' für
alle x), auf keinen Fall aber irgendwas in der Mitte. Entsprechend
kannst Du zwar

LIKE 'foo%'

noch indizieren

LIKE '%foo%'

aber nicht mehr.

> Deshalb lassen sich statt (äusserlichen) Stringvergleichen auch
> Binäroperationen mit dem Feldwert durchführen, etwa ob der SET-Feldwert
> 'red' enthält:
>
> SELECT …
> FROM …
> WHERE `properties` & 4
>
> bzw.
>
> SELECT …
> FROM …
> WHERE `properties` & 4 > 0
>
> Gleichermassen darf angenommen werden, dass das die Form der Abfrage nach
> Optimierung von
>
> SELECT …
> FROM …
> WHERE FIND_IN_SET('red', `properties`) > 0
>
> durch die Engine ist. Immerhin *muss* die Engine den Wert 'red' zur
> entsprechenden Zweierpotenz auflösen, wenn sie ein sinnvolles
> Abfrageergebnis liefern soll.

Ganz genau. Und genau deswegen ist Dein Index wertlos.

> Und es gibt keinen guten Grund, weshalb sich diese ganzzahligen Werte nicht
> wie alle anderen Zahlenwerte indizieren lassen sollten.

Sie lassen sich natürlich indizieren, das hat niemand bestritten. Aber
Du kannst mit diesem Index bei der Suche nach einzelnen Bits nichts
anfangen. Ebenso hilft Dir der schönste Index bei LIKE '&xxx%' nichts.
Das ist direkt vergleichbar. Da kannst Du Dir noch so oft sagen "Aber
Zeichenketten sind doch indizierbar!" und dabei am besten noch mit dem
Fuß aufstampfen. Solange Du die nötigen Zusammenhänge, inwiefern
Indizes überhaupt verwendet werden können a) nicht verstanden hast und
Dich b) hartnäckig weigerst, Deine diesbezüglichen Defizite
auszugleichen, sind Diskussionen dazu mit Dir reichlich sinnfrei.




Bernd
0 new messages