Unterschied Mysql-Max und Mysql-Save

MySQL, PostgreSQL, SQLite
greenrover
Posts: 203
Joined: 2004-12-17 19:34

Unterschied Mysql-Max und Mysql-Save

Post by greenrover » 2006-01-26 17:04

Was sit eigentlich der genau Unterschied zwischen
Mysql-Max und Mysql-Save

Und was bedeuten diese für mich wenn das ganze für einen Webserver verwendet wird. Also Datenbanktype MyIsam ist.

Und ist ein Performance-unterschied zu merken?

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Unterschied Mysql-Max und Mysql-Save

Post by isotopp » 2006-01-26 18:47

GreenRover wrote:Was ist eigentlich der genau Unterschied zwischen Mysql-Max und Mysql-Save
mysql_safe ist der Wrapper für MySQL. Er startet den eigentlichen Datenbankserver, mysqld oder mysqld-max.

mysqld enthält Support für alles, was man normalerweise mit einem MySQL Server machen will. mysqld-max unterscheidet sich wie folgt: 4.1, 5.0.

In MySQL 4.x und höher ist also InnoDB immer enthalten, auch in Nicht-Max. -Max enthält zusätzlich bdb, blackhole, example und ndbcluster (das brauchst Du alles nicht) und unter Windows Symlink-Support (das ist in Linux automatisch drin).

Wenn Du MyISAM verwendest, brauchst Du mysqld-max nicht und kannst mit dem normalen mysql-Binary arbeiten.

greenrover
Posts: 203
Joined: 2004-12-17 19:34

Re: Unterschied Mysql-Max und Mysql-Save

Post by greenrover » 2006-01-31 14:15

Danke für die Infos.

Kannst du mir auch noch ein paar tips geben wie man einen Mysql 5 Server auf Performance optimiert.

Und mir sagen was man bei dieser Meldung optimierne muß:

Code: Select all

Handler_read_rnd_next  	4,25 G 

Anzahl der Anfragen, die nächste Zeile in der Daten-Datei zu lesen. Dieser Wert wird hoch sein, wenn Sie viele Tabellen-Scans durchführen. Im Allgemeinen weist das darauf hin, dass Ihre Tabellen nicht korrekt indiziert sind, oder dass Ihre Anfragen nicht so geschrieben sind, dass Sie Vorteile aus den Indexen ziehen, die Sie haben.
Also wird das durch SELECT * FROM ... verursacht oder wodurch ???


Und Handler_read_rnd 43 M ist auch sehr hoch oder ???

Sonstige Serverdaten:

Abfrageart ø pro Stunde %
select 7 M 59,71 k 90,18%
delete 90 k 772,95 1,17%
set option 24 k 209,63 0,32%
show create table 21 k 181,50 0,27%
change db 423 k 3,63 k 5,48%
show triggers 21 k 180,69 0,27%
update 99 k 848,05 1,28%
insert 30 k 257,43 0,39%

Die Restlichen nicht aufgeführten werte sind nahezu 0

Es würde mir würklich sehr helfen wenn mir jemand ein paar ips / links geben könnten.

Danke euch im Vorraus.

EDIT: Die Taten bezihen sich auf eine Laufzeit von:
4 Tage, 20 Stunden und 8.035.815 Query´s

oxygen
Posts: 2138
Joined: 2002-12-15 00:10
Location: Bergheim

Re: Unterschied Mysql-Max und Mysql-Save

Post by oxygen » 2006-01-31 16:16

Ja ein SELECT * FROM ist ja schonmal nicht ganz optimal. Aber mit richtigen Indexes oder Keys liese sich das schon verbessern.

greenrover
Posts: 203
Joined: 2004-12-17 19:34

Re: Unterschied Mysql-Max und Mysql-Save

Post by greenrover » 2006-01-31 19:15

Ich habe jetzt indexes gesetzt, aber leider mit mäsigen erfolg.

Habe schon wieder:
Handler_read_rnd_next 43 M

und das mit den SELECT * FROM naja das kann noch dauern bis ich die alle habe, das script ist leidern icht ganz so klein, so das da doch einiger müll drin versteckt ist.

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Unterschied Mysql-Max und Mysql-Save

Post by isotopp » 2006-01-31 22:28

GreenRover wrote:Kannst du mir auch noch ein paar tips geben wie man einen Mysql 5 Server auf Performance optimiert.
Kann ich. Da verdiene ich meinen Lebensunterhalt mit. Wie lang willst Du es haben? MySQL PT Workshop, 3 Tage, 234 Slides?

Code: Select all

Handler_read_rnd_next  	4,25 G

Anzahl der Anfragen, die nächste Zeile in der Daten-Datei zu lesen. Dieser Wert wird hoch sein, wenn Sie viele Tabellen-Scans durchführen. Im Allgemeinen weist das darauf hin, dass Ihre Tabellen nicht korrekt indiziert sind, oder dass Ihre Anfragen nicht so geschrieben sind, dass Sie Vorteile aus den Indexen ziehen, die Sie haben.
Aktiviere das Slow Query Log. Analysiere es mit mysqldumpslow, um Queries zu finden, die oft ausgeführt werden und langsam sind.

Suche Dir konkrete Instanzen dieser Queries mit Werten drin und verwende EXPLAIN für diese Queries. Wende die Erkenntnisse aus dem Kapitel über Optimierung, insbesondere How to avoid table scans an.

Ansonsten sind 20 Selects pro Sekunde (60000/3600 = ~20) nicht sehr viel. Und 180 SHOW TRIGGERS pro Stunden sind Unsinn - was ist da kaputt?

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Unterschied Mysql-Max und Mysql-Save

Post by isotopp » 2006-01-31 22:32

GreenRover wrote:SELECT * FROM
SELECT * bezieht sich auf Spalten. Das ist erst einmal sekundär. Deine Meßwerte beziehen sich auf Zeilen und wie sie gefunden werden. Da geht es also um JOIN- Bedingungen in ON- und WHERE-Clauses, und ob dafür Indices verwendet werden können.

Also finde die Queries, die langsam sind (slow query log) und dann wende EXPLAIN auf die Queries an - werden die Indices verwendet? Wenn ja, wie groß ist der Result Set der Query und was ist die Badness der Query im Vergleich?

Eine Query mit einem Result Set von 1000 Zeilen kann keine Badness kleiner als 1000 haben. Wenn im Explain aber drei Zeilen stehen, die alle SIMPLE sind, und das Produkt der "Rows"-Werte 10.000 ist, dann werden 10.000 Zeilen angefaßt, um 1.000 Zeilen zu produzieren -die Badness ist also 10.000 statt 1.000 wie sie sein könnte.

greenrover
Posts: 203
Joined: 2004-12-17 19:34

Re: Unterschied Mysql-Max und Mysql-Save

Post by greenrover » 2006-02-01 15:29

Also viel vielen Dank für deien Antwort, ich werde mic hdamit mal probieren. Und solltem ir wohl einen solchen Workshop doch mal genehmigen. Aber die Anzhal der Trigger pro Stunde ist schon auf: 251,20.

Was sagt das überhaupt aus ???

Und slow Query`s waren die letzten 24 Stunden nur einer, den ich aber leider nicht mitgelogt habe. log läuft siet 5min

Und 20 Selects die Sekunde ??? so wenig. Also ich hätte mindestens etwas über 300 erwartet. Aber mom läuft auch nicht viel.

Und eigentlich produziert das System nur recht einfache Query`s die nur auf eienr Tabelle sind aber teilweise etwas aufwendigeren WHERE haben.

Aber ich lese mir das Tutorial lieber erstmal durch.

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Unterschied Mysql-Max und Mysql-Save

Post by isotopp » 2006-02-01 15:38

GreenRover wrote:Und solltem ir wohl einen solchen Workshop doch mal genehmigen.
Ja, aber Werbung ist hier verboten, deswegen darf ich Dich nicht auf http://www.mysql.com/consulting/ hinweisen.
Aber die Anzahl der Trigger pro Stunde ist schon auf: 251,20. Was sagt das überhaupt aus ???
Was genau?

Code: Select all

root@localhost [(none)]> show status like "%trig%";
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| Com_show_triggers | 0     |
+-------------------+-------+
1 row in set (0.00 sec)
Die com_ Counter zählen, wie oft ein bestimmtes Kommando (hier: SHOW TRIGGERS) ausgeführt wird. 251 SHOW TRIGGER pro Stunde sind mindestens komisch. Was erzeugt diese Anweisungen?
Und 20 Selects die Sekunde ??? so wenig. Also ich hätte mindestens etwas über 300 erwartet. Aber mom läuft auch nicht viel.
Im Durchschnitt. 86400 Sekunden am Tag, also sind 100000 Selects am Tag in etwa ein Select pro Sekunde. 20 Select pro Sekunde sind also etwa 2 Mio Select am Tag.

greenrover
Posts: 203
Joined: 2004-12-17 19:34

Re: Unterschied Mysql-Max und Mysql-Save

Post by greenrover » 2006-02-01 15:58

OK kannst du mir nochmals helfen:

Habe meinen ersten long Query...

Code: Select all

mysql> EXPLAIN SELECT * FROM news_news WHERE (title REGEXP 'liege|liege' OR main_text REGEXP 'liege|liege' OR input_1 REGEXP 'liege|liege' OR input_2 REGEXP 'liege|liege' OR input_3 REGEXP 'liege|liege' OR input_4 REGEXP 'liege|liege') AND kat_id='100' ORDER BY date DESC;
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                                               |
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE noticed after reading const tables |
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
1 row in set (0.00 sec)
Ich denke mal ein FULTEXT auf main_text, input_1, input_2, input_3 und input_4 legen um das zuverbessern oder?

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Unterschied Mysql-Max und Mysql-Save

Post by isotopp » 2006-02-01 16:38

[quote="GreenRover"]

Code: Select all

+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                                               |
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE noticed after reading const tables |
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
1 row in set (0.00 sec)
Diese Query ist nicht langsam, oder Du zeigst nicht das richtige EXPLAIN, denn EXPLAIN sagt hier: "Impossible WHERE noticed", d.h. diese Query findet genau gar keine Daten für diese Suchbegriffe.

Wenn Du die Query ohne EXPLAIN ausführst (also nur das SELECT), wirst Du 0 rows returned sehen, und eine sehr kurze Ausführungszeit.

Code: Select all

SELECT * 
FROM news_news 
WHERE (title REGEXP 'liege|liege' OR main_text REGEXP 'liege|liege' OR input_1 REGEXP 'liege|liege' OR input_2 REGEXP 'liege|liege' OR input_3 REGEXP 'liege|liege' OR input_4 REGEXP 'liege|liege') AND kat_id='100' ORDER BY date DESC;
Es gibt verschiedene Möglichkeiten, das zu verbessern. Eine ist ein FULLTEXT Index (wenn die Tabelle MyISAM ist, InnoDB kann kein FULLTEXT).

REGEXP ist hier für diesen Suchtext auch Overkill. Ich nehme an, Du willst hier eigenlich kompliziertere Suchausdrücke haben?

Wieso mußt Du 5 Spalten nach denselben Sachen durchsuchen, und wieso haben die Spalten alle denselben Namen mit Nummern drin? Dein Schema macht den Eindruck, als sei es nicht korrekt normalisiert.

Eine Tabelle (id, a1, a2, a3, a4, a5) mit primary key id sollte man nach (id, nr, a) mit primary key (id, nr) normalisieren. Du kannst dann ja die Ausgangstabelle mit einem VIEW simulieren für Legacy Anwendungen.

greenrover
Posts: 203
Joined: 2004-12-17 19:34

Re: Unterschied Mysql-Max und Mysql-Save

Post by greenrover » 2006-02-01 16:51

JA das system ist leider kaum vernüftig normalisiert worden. Aber das wurde auch zum größten Teil vor meiner Zeit entwickelt.

Aber das habe ich mir jetzt mahl erspart zu verändern, das es 4 felder sind denen man variabelle namen zuweisen kann. Diese sind aber zum größten teil ausgefüllt und daher ist es ja wieder egal.

Das was du siehst, ist der query großen fulltextsuche des Systems. beidem alle Datenfelder durchsucht werden.

Und das mit dem regex wird definitv ein overkill sein, aber es soll halt jeder begriff überprüft werden ob er vorhanden ist jeweils OR und dazu auch noch OR auf das haupt Textfeld und die 4 variabellen Textfelder.

Und der SQL Server wird es vermutlich als long query identifiziert haben das es wohl dauert ~ 1300 Zeilen in 4 Felder mit REGEX zu suchen oder ??? ..... das sind alles Felder des Types Text und auch wirklich daten drinn. Von meistens 1000-2000 Zeichen.

Und genau diese Suche abfrage ist jetzt schon mehrfach in log.

Wie würdest du solch eine suchabfrage gestatlen???

wenn in allen 3 Felder z.B. nach A, B und C gesucht werden sollte ??

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Unterschied Mysql-Max und Mysql-Save

Post by isotopp » 2006-02-01 21:01

GreenRover wrote:Und der SQL Server wird es vermutlich als long query identifiziert haben das es wohl dauert ~ 1300 Zeilen in 4 Felder mit REGEX zu suchen oder ??? ..... das sind alles Felder des Types Text und auch wirklich daten drinn. Von meistens 1000-2000 Zeichen.

Code: Select all

# mysql-instance /export/data/rootforum 5.0.17 3340
Creating 5.0.17 instance
  from mysql-max-5.0.17-linux-i686-glibc23/
  in /export/data/rootforum,
  listening on port 3340
# mysqlstart-3340
# mysql-3340 -u root
root@localhost [none]> create database greenrover;
root@localhost [none]> use greenrover;
root@localhost [greenrover]> create table t (
  `id` serial,
  `title` text NOT NULL,
  `main_text` text NOT NULL,
  `input_1` text NOT NULL,
  `input_2` text NOT NULL,
  `input_3` text NOT NULL,
  `input_4` text NOT NULL,
  `kat_id` int(10) unsigned NOT NULL,
);
Also bauen wir mal ein paar Daten dafür.

Code: Select all

kris@linux:~> cat greenrover.pl
#! /usr/bin/perl --

use DBI;
use DBD::mysql;

my $dsn = "DBI:mysql:database=greenrover;host=127.0.0.1;port=3340";
my $dbh = DBI->connect($dsn, "root");
$dbh->{RaiseError} = 1;

my $rows = 1300;      # Zeilen in der Tabelle
my $fieldlen = 1300;  # Mindestlänge der Textfelder

# Beispielworte für Einträge
open IN, "</usr/share/dict/words" or die;
@words = <IN>;
close IN;
chomp @words;

$words = $#words;

for (my $i=0; $i<$rows; $i++) {
  # Kram in Tabelle t reinscheppern
  my $sth = $dbh->prepare("insert into t ( id, kat_id, title, main_text, input_1, input_2, input_3, input_4 ) values ( NULL, ?, ?, ?, ?, ?, ?, ?)");

  # 20% aller Einträge sind kat_id = 100, der Rest ist Random
  $sth->bind_param(1, rand()<0.2?100:rand()*1000);

  # Baue Einträge aus wirren Worten
  for (my $j=2; $j<=7; $j++) {
    my $str = "";
    while (length($str) < $fieldlen) {
      $str .= $words[rand*$words];
    }
    $sth->bind_param($j, $str);
  }

  # Schuß!
  $sth->execute();
}
Wie ist die Lage denn so?

Code: Select all

root@localhost [greenrover]> analyze table t;
+--------------+---------+----------+-----------------------------+
| Table        | Op      | Msg_type | Msg_text                    |
+--------------+---------+----------+-----------------------------+
| greenrover.t | analyze | status   | Table is already up to date |
+--------------+---------+----------+-----------------------------+
1 row in set (0.00 sec)
root@localhost [greenrover]> show table status like "t"G
*************************** 1. row ***************************
           Name: t
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1300
 Avg_row_length: 8103
    Data_length: 10535136
Max_data_length: 281474976710655
   Index_length: 11276288
      Data_free: 0
 Auto_increment: 6613
    Create_time: 2006-02-01 20:21:22
    Update_time: 2006-02-01 20:21:22
     Check_time: 2006-02-01 20:21:30
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)
Jetzt können wir mal Queries fahren.

Code: Select all

root@localhost [greenrover]> select id 
 from t 
where title regexp 'melissa|melissa' 
   or main_text regexp 'melissa|melissa' 
   or input_1 regexp  'melissa|melissa' 
   or input_2 regexp 'melissa|melissa' 
   or input_3 regexp 'melissa|melissa' 
   or input_4 regexp 'melissa|melissa';
+------+
| id   |
+------+
| 5313 |
| 5464 |
| 5542 |
| 5729 |
| 5911 |
| 6156 |
| 6168 |
| 6296 |
| 6538 |
| 6553 |
| 6588 |
| 6610 |
+------+
12 rows in set (3.58 sec)
root@localhost [greenrover]> explain select id 
 from t 
where title regexp 'melissa|melissa' 
   or main_text regexp 'melissa|melissa' 
   or input_1 regexp  'melissa|melissa' 
   or input_2 regexp 'melissa|melissa' 
   or input_3 regexp 'melissa|melissa' 
   or input_4 regexp 'melissa|melissa'G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 1300
        Extra: Using where
1 row in set (0.00 sec)
So ganz ohne Index saugt das in der Tat gewaltig. Mit der Abfrage auf kat_id kann man das besser hin bekommen, wenn ein Index auf kat_id liegt.

Code: Select all

root@localhost [greenrover]> alter table t add index (kat_id);
Query OK, 1300 rows affected (7.91 sec)
Records: 1300  Duplicates: 0  Warnings: 0
Nun sieht das immerhin schon so aus:

Code: Select all

root@localhost [greenrover]> select id 
 from t 
where kat_id = 100 
and ( 
    title regexp 'melissa|melissa' 
 or main_text regexp 'melissa|melissa' 
 or input_1 regexp 'melissa|melissa' 
 or input_2 regexp 'melissa|melissa' 
 or input_3 regexp 'melissa|melissa' 
 or input_4 regexp 'melissa|melissa' 
);
+------+
| id   |
+------+
| 5729 |
| 5911 |
| 6553 |
| 6588 |
+------+
4 rows in set (0.71 sec)
Der zugehörige Explain faßt dann auch brav nur noch 260 statt 1300 rows an:

Code: Select all

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
         type: ref
possible_keys: kat_id
          key: kat_id
      key_len: 4
          ref: const
         rows: 260
        Extra: Using where
1 row in set (0.00 sec)

root@localhost [greenrover]> select 3.58/0.71 as speedup G
*************************** 1. row ***************************
speedup: 5.042254
1 row in set (0.00 sec)
Mit FULLTEXT geht das aber noch besser:

Code: Select all

root@localhost [greenrover]> alter table t add fulltext f (title, main_text, input_1, input_2, input_3, input_4 );
Query OK, 1300 rows affected (17.23 sec)
Records: 1300  Duplicates: 0  Warnings: 0
root@localhost [greenrover]> show table status like "t"G
*************************** 1. row ***************************
           Name: t
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 1300
 Avg_row_length: 8103
    Data_length: 10535136
Max_data_length: 281474976710655
   Index_length: 22517760
      Data_free: 0
 Auto_increment: 6613
    Create_time: 2006-02-01 20:38:42
    Update_time: 2006-02-01 20:38:42
     Check_time: 2006-02-01 20:39:00
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)
Für eine Data Length von 10MB haben wir jetzt aber eine Index Length von 22MB. Die Queries sind dafür aber superschnell:

Code: Select all

root@localhost [greenrover]> select id, match(title, main_text, input_1, input_2, input_3, input_4) against ('melissa') as rank 
 from t 
where kat_id = 100 
  and match(title, main_text, input_1, input_2, input_3, input_4) against ('melissa');
+------+------------------+
| id   | rank             |
+------+------------------+
| 5729 | 0.81813311576843 |
| 5911 | 0.48297706246376 |
| 6553 | 0.48286464810371 |
| 6588 | 0.48263877630234 |
+------+------------------+
4 rows in set (0.00 sec)
Laut EXPLAIN wird der FULLTEXT präferiert:

Code: Select all

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: t
         type: fulltext
possible_keys: kat_id,f
          key: f
      key_len: 0
          ref:
         rows: 1
        Extra: Using where
1 row in set (0.00 sec)
Die Badness ist nun auf eine Schätzung von 1 (tatsächlich gefunden: 4) runter. Die Zeit ist nicht mehr meßbar.

Zum Vergleich hier die Normalisierung:

Code: Select all

root@localhost [greenrover]> CREATE TABLE `tt` (
  `id` serial,
  `kat_id` int(10) unsigned NOT NULL,
  KEY `kat_id` (`kat_id`)
);
root@localhost [greenrover]> CREATE TABLE `tt_txt` (
  `id` bigint(20) unsigned NOT NULL,
  `type` int(10) unsigned NOT NULL,
  `txt` text NOT NULL,
  PRIMARY KEY  (`id`,`type`)
);
root@localhost [greenrover]> insert into tt select id, kat_id from t;
Query OK, 1300 rows affected (0.03 sec)
Records: 1300  Duplicates: 0  Warnings: 0

root@localhost [greenrover]> insert into tt_txt 
select id, 1, input_1 from t 
union 
select id, 2, input_2 from t 
union 
select id, 3, input_3 from t 
union 
select id, 4, input_4 from t 
union 
select id, 5, title from t 
union 
select id, 6, main_text from t;
Query OK, 7800 rows affected (0.84 sec)
Records: 7800  Duplicates: 0  Warnings: 0
Die Query sieht dann so aus:

Code: Select all

root@localhost [greenrover]> select distinct tt.id 
 from tt join tt_txt on tt.id = tt_txt.id 
where tt.kat_id = 100 
  and tt_txt.txt regexp 'melissa';
+------+
| id   |
+------+
| 5729 |
| 5911 |
| 6553 |
| 6588 |
+------+
4 rows in set (0.36 sec)
Wie man sieht, ist die Query nicht nur sehr viel einfacher als der fette OR-Ausdruck, sondern sie ist auch noch 10 mal schneller. Normalisierung lohnt sich. Die Badness ist, wie man im EXPLAIN sieht, 260 * 6 (260 Rows haben kat_id = 100, und pro Row haben wir 6 Textfelder).

Code: Select all

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tt
         type: ref
possible_keys: id,kat_id
          key: kat_id
      key_len: 4
          ref: const
         rows: 260
        Extra: Using temporary
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: tt_txt
         type: ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 8
          ref: greenrover.tt.id
         rows: 6
        Extra: Using where; Distinct
2 rows in set (0.01 sec)
Für einen Result-Set von 4 ist das aber immer noch fast 400 mal zu viel.

So sieht es normalisiert mit FULLTEXT aus:

Code: Select all

root@localhost [greenrover]> alter table tt_txt add fulltext f (txt);
Query OK, 7800 rows affected (9.37 sec)
Records: 7800  Duplicates: 0  Warnings: 0
root@localhost [greenrover]> show table status like "tt_txt"G
*************************** 1. row ***************************
           Name: tt_txt
         Engine: MyISAM
        Version: 10
     Row_format: Dynamic
           Rows: 7800
 Avg_row_length: 1365
    Data_length: 10648904
Max_data_length: 281474976710655
   Index_length: 13569024
      Data_free: 0
 Auto_increment: NULL
    Create_time: 2006-02-01 20:56:42
    Update_time: 2006-02-01 20:56:43
     Check_time: 2006-02-01 20:56:52
      Collation: utf8_general_ci
       Checksum: NULL
 Create_options:
        Comment:
1 row in set (0.00 sec)
root@localhost [greenrover]> select distinct tt.id from tt join tt_txt on tt.id = tt_txt.id where kat_id = 100 and match(tt_txt.txt) against('melissa');
+------+
| id   |
+------+
| 5729 |
| 6553 |
| 6588 |
| 5911 |
+------+
4 rows in set (0.00 sec)

root@localhost [greenrover]> explain select distinct tt.id from tt join tt_txt on tt.id = tt_txt.id where kat_id = 100 and match(tt_txt.txt) against('melissa')G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: tt_txt
         type: fulltext
possible_keys: PRIMARY,f
          key: f
      key_len: 0
          ref:
         rows: 1
        Extra: Using where; Using temporary
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: tt
         type: eq_ref
possible_keys: id,kat_id
          key: id
      key_len: 8
          ref: greenrover.tt_txt.id
         rows: 1
        Extra: Using where
2 rows in set (0.00 sec)
Wie man sieht, zieht der Optimizer im JOIN die tt_txt mit dem Fulltext Index f nach vorne, weil dieser selektiver ist (Badness wird mit 1 angenommen), und joined dann tt dagegen über die id. Das ist ein eq_ref, weil die id in tt eindeutig ist, sodaß wir hier eine fast "perfekte" Query hin bekommen: Für jeden Treffer auf dem FULLTEXT wird die passende Zeile in tt direkt Zugegriffen (eq_ref) und dann noch mit WHERE weiter nach kat_id = 100 gefiltert (dafür kann dann kein Index mehr verwendet werden).

Willst Du nun nicht nur nach "melissa" suchen, nimmst Du drei dieser Queries und setzt die mit UNION zusammen, um ein OR zu bekommen. Da dies drei hocheffiziente Queries sind, und das UNION nach diesen Queries gemacht wird, bleibt auch die Gesamtquery so hocheffizient.

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Unterschied Mysql-Max und Mysql-Save

Post by isotopp » 2006-02-01 21:09

Alle Beispiele gerechnet auf einem MySQL 5.0.17 auf Suse 10.0 auf einem Dell Latitude D810 Laptop (Pentium M 1.86GHz) mit einer 7200rpm SATA Laptop-Platte drin.

key_buffer war in der my.cnf auf 300M gesetzt (also viel zu groß: In der Prozeßliste ist bei der Instanz RES ist während des Arbeitens nur auf 59M geklettert und dann stehen geblieben, potentiell wären laut VIRT 342M drin gewesen).

greenrover
Posts: 203
Joined: 2004-12-17 19:34

Re: Unterschied Mysql-Max und Mysql-Save

Post by greenrover » 2006-02-02 11:31

OK, das mti der normalierung muß ich dann auch mal machen, aber mom fehlt mir die zeit dazu dann alles im script zu ändern.

Aber vielen vielen Dank für deine Tips, ich habe jetzt mall die fulltext key`s gesetzt.

nun Muß ich dann nur noch die stellen im code finden wo die "SELECT * FROM `news_news`" ausgeführt werden .... das ist die Tabelle die du dier nachgebaut hast.

Ã?brigens machst du dir öfter solch eien reisen Arbeit um sowas zu testen ??? Ist ja Wahnsinn.

Und ich bin jetzt echt mal gespannt, bei welchem Ansturm der Server das nächste mal zusammen klappt. Also nicht das wieder bei 32.0000 Besucher/ Tag alles zu ist.

User avatar
isotopp
Posts: 471
Joined: 2003-08-21 10:21
Location: Berlin

Re: Unterschied Mysql-Max und Mysql-Save

Post by isotopp » 2006-02-02 14:17

GreenRover wrote:Ã?brigens machst du dir öfter solch eien reisen Arbeit um sowas zu testen ??? Ist ja Wahnsinn.
Das ist mein Job. Dein Beispiel zu Rechnen hat weniger als 10 Minuten gedauert.

greenrover
Posts: 203
Joined: 2004-12-17 19:34

Re: Unterschied Mysql-Max und Mysql-Save

Post by greenrover » 2006-02-02 14:36

So ich bin jetzt durch mit der Seitenoptimierung.

Und konnte eine ver 10fachung der Leistung ereichen.

Wobei aber PHP Coder und SQL abfragen angepasst wurden.

Und der Code wohl mehr, da das mein Gebiebt ist.