Februar 2010 Archive

Zu Sehen ist die römische Dekadenz an jeder Armenküche, an der die Menschen faul anstehen, um sich den Wanst vollzuschlagen.
Aus den Opfern unserer Gesellschaft Täter zu machen, damit ihnen Schuld aufzubürden und sich so von Verantwortung zu befreien, ist ein altes Spiel.
Das Prekariat in unserer Gesellschaft haben wir alle zu verantworten und einem Kind quasi ins Gesicht zu sagen: "Du und Deine Eltern, Ihr seid wertlos!" ist übelste Hetze. Und auf diese werden nun als Mitte benannte (Kellner, Friseure etc.) gehetzt. Also Angehörige einer Schicht, welche selbst randständig prekär ist. Diese dürfen sich im Hass, als Mitte imaginieren.

Wer am Ende behauptet, dass Kinder unsere Zukunft sind, kapiert wohl nicht, dass er diese gerade zerstört hat.


Partitionierung gibt es seit MySQL 5.1. Eine sehr praktische Technik mit Eigenheiten:

Gewohnt jeder Tabelle einen PK zu geben, aber nicht nach dem PK, sondern nach einer anderen Spalte - hier jahr - zu partitionieren, antwortet MySQL wiefolgt:


mysql> create table au ( id int not null auto_increment key, jahr date, wichtig int) engine=myisam partition by range(year(jahr))
(PARTITION p0 VALUES LESS THAN(2000),
PARTITION p1 VALUES LESS THAN(2005),
PARTITION p2 VALUES LESS THAN(2010),
PARTITION p3 VALUES LESS THAN(MAXVALUE));
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table's partitioning function
Hierbei handelt es sich um eine dokumentierte Einschränkung:

All columns used in the partitioning expression for a partitioned table must be part of every unique key that the table may have .. RTFM 

Sprich ein UNIQUE Index über (id,date) würde nicht mehr zu einer Fehlermeldung führen:

mysql> create table au ( id int not null auto_increment, jahr date, wichtig int,  primary key  `aaa` (id,jahr)) engine=myisam partition by range(year(jahr))
(PARTITION p0 VALUES LESS THAN(2000),
PARTITION p1 VALUES LESS THAN(2005),
PARTITION p2 VALUES LESS THAN(2010),
PARTITION p3 VALUES LESS THAN(MAXVALUE));
Query OK, 0 rows affected (0,01 sec)

Gut! Nun ist aber id nicht mehr UNIQUE .. schlecht!

Den einzigen Würgaround, den ich bis dato gefunden habe, ist die Checks auf UNIQUE in eine andere Tabelle auszulagern und mit einem Trigger zu "prüfen".

mysql> CREATE TABLE id_check (id int KEY);
Query OK, 0 rows affected (0,01 sec)
mysql> CREATE TRIGGER `unique_chk_trg` BEFORE INSERT ON au FOR EACH ROW INSERT INTO id_check VALUES(NEW.id);
Query OK, 0 rows affected (0,00 sec)
Desgleichen noch für UPDATE und DELETE. Diese Lösung kostet natürlich Performance und die Trigger werden z.B. bei einem TRUNCATE nicht abgefeuert.

Wieso Weshalb Warum (ist das so?)

Ein Blick ins Dateisystem zeigt, warum - wenn vorhanden - via UNIQUE Indizes partitioniert werden muss.
> ls -1 au*I
au#P#p0.MYI
au#P#p1.MYI
au#P#p2.MYI
au#P#p3.MYI
Dies war der Grund warum ENGINE=MyISAM verwendet wurde (was man eigentlich nicht mehr will).  Bei MyISAM sind die Indexdateien (MYI) im Dateisystem sichtbar und man erkennt hier, dass die vier Partitionen separate Index-Dateien haben. Würden nun UNIQUE-Indizes nicht Teil der Partitionierungslogik sein, könnte über die disjunkten Dateien hinweg nicht mehr garantiert werden, dass UNIQUE Indizes weiterhin UNIQUE sind.


Fun mit civicrm

| 1 Kommentar | Keine TrackBacks
Heute schlug eine nette Query aus civicrm in #mysql.de auf

 SELECT DISTINCT UPPER(LEFT(contact_a.sort_name, 1)) as sort_name  
FROM civicrm_contact contact_a
LEFT JOIN civicrm_group_contact `civicrm_group_contact-101`
ON contact_a.id = `civicrm_group_contact-101`.contact_id
LEFT JOIN civicrm_group_contact `civicrm_group_contact-102`
ON contact_a.id = `civicrm_group_contact-102`.contact_id
LEFT JOIN civicrm_group_contact `civicrm_group_contact-46`
ON contact_a.id = `civicrm_group_contact-46`.contact_id
LEFT JOIN civicrm_group_contact `civicrm_group_contact-60`
ON contact_a.id = `civicrm_group_contact-60`.contact_id
LEFT JOIN civicrm_group_contact `civicrm_group_contact-6`
ON contact_a.id = `civicrm_group_contact-6`.contact_id
LEFT JOIN civicrm_group_contact `civicrm_group_contact-94`
ON contact_a.id = `civicrm_group_contact-94`.contact_id
LEFT JOIN civicrm_group_contact `civicrm_group_contact-95`
ON contact_a.id = `civicrm_group_contact-95`.contact_id
LEFT JOIN civicrm_group_contact `civicrm_group_contact-97`
ON contact_a.id = `civicrm_group_contact-97`.contact_id
LEFT JOIN civicrm_group_contact `civicrm_group_contact-99`
ON contact_a.id = `civicrm_group_contact-99`.contact_id
LEFT JOIN civicrm_group_contact_cache `civicrm_group_contact_cache_6`
ON contact_a.id = `civicrm_group_contact_cache_6`.contact_id
WHERE
(
(
( `civicrm_group_contact-6`.group_id IN ( 6 )
AND
`civicrm_group_contact-6`.status IN ("Added" )
)
OR
( `civicrm_group_contact_cache_6`.group_id = 6
)
)
)
AND
(
( `civicrm_group_contact-6`.group_id IN ( 6 )
AND `civicrm_group_contact-6`.status IN ("Added")
)
OR
( `civicrm_group_contact-46`.group_id IN ( 46 )
AND `civicrm_group_contact-46`.status IN ("Added")
)
OR
( `civicrm_group_contact-60`.group_id IN ( 60 )
AND `civicrm_group_contact-60`.status IN ("Added")
) OR ( `civicrm_group_contact-94`.group_id IN ( 94 )
AND `civicrm_group_contact-94`.status IN ("Added") )
OR ( `civicrm_group_contact-95`.group_id IN ( 95 )
AND `civicrm_group_contact-95`.status IN ("Added") )
OR ( `civicrm_group_contact-97`.group_id IN ( 97 )
AND `civicrm_group_contact-97`.status IN ("Added") )
OR ( `civicrm_group_contact-99`.group_id IN ( 99 )
AND `civicrm_group_contact-99`.status IN ("Added") )
OR ( `civicrm_group_contact-101`.group_id IN ( 101 )
AND `civicrm_group_contact-101`.status IN ("Added") )
OR ( `civicrm_group_contact-102`.group_id IN ( 102 )
AND `civicrm_group_contact-102`.status IN ("Added") ) );

Was sich die Entwickler dabei dachten ist mir nicht klar, denn es ist nichts anderes als

SELECT DISTINCT UPPER(LEFT(contact_a.sort_name, 1)) as sort_name
FROM civicrm_contact contact_a;

Sprich die Menge aller Großbuchstaben des ersten Buchstaben von sort_name.

*kopfkratz*

Danke an Rince der mit der Query in #mysql.de aufschlug.
Wer Lust hat ist gerne eingeladen auch im irc aufzuschlagen:)