Versteckte Funktionen von MySQL


101

Ich arbeite seit vielen Jahren mit Microsoft SQL Server , habe aber erst vor kurzem begonnen, MySQL mit meinen Webanwendungen zu verwenden, und bin hungrig nach Wissen.

Um mit der langen Reihe von Fragen zu "versteckten Funktionen" fortzufahren , möchte ich alle versteckten oder praktischen Funktionen von MySQL kennen, die hoffentlich mein Wissen über diese Open-Source-Datenbank verbessern.

Antworten:


161

Da Sie ein Kopfgeld aufbringen, werde ich meine hart erkämpften Geheimnisse teilen ...

Im Allgemeinen mussten für alle SQLs, die ich heute optimiert habe, Unterabfragen verwendet werden. Aus der Oracle-Datenbankwelt stammend, funktionierten Dinge, die ich für selbstverständlich hielt, mit MySQL nicht gleich. Und meine Lektüre über MySQL-Tuning lässt mich zu dem Schluss kommen, dass MySQL bei der Optimierung von Abfragen hinter Oracle steht.

Während die einfachen Abfragen, die für die meisten B2C-Anwendungen erforderlich sind, für MySQL gut funktionieren können, scheint der Großteil der für Intelligence Reporting erforderlichen aggregierten Berichterstellungstypen einiges an Planung und Neuorganisation der SQL-Abfragen zu erfordern, damit MySQL sie schneller ausführen kann.

Verwaltung:

max_connectionsist die Anzahl der gleichzeitigen Verbindungen. Der Standardwert ist 100 Verbindungen (151 seit 5.0) - sehr klein.

Hinweis:

Verbindungen beanspruchen Speicher und Ihr Betriebssystem kann möglicherweise nicht viele Verbindungen verarbeiten.

Mit MySQL-Binärdateien für Linux / x86 können Sie bis zu 4096 gleichzeitige Verbindungen herstellen, selbst kompilierte Binärdateien sind jedoch häufig weniger begrenzt.

Stellen Sie table_cache so ein, dass es mit der Anzahl Ihrer geöffneten Tabellen und gleichzeitigen Verbindungen übereinstimmt. Beobachten Sie den Wert von open_tables. Wenn er schnell wächst, müssen Sie ihn vergrößern.

Hinweis:

Die beiden vorherigen Parameter erfordern möglicherweise viele geöffnete Dateien. 20 + max_connections + table_cache * 2 ist eine gute Schätzung für das, was Sie benötigen. MySQL unter Linux verfügt über die Option open_file_limit. Legen Sie dieses Limit fest.

Wenn Sie komplexe Abfragen haben, sind sort_buffer_size und tmp_table_size wahrscheinlich sehr wichtig. Die Werte hängen von der Komplexität der Abfrage und den verfügbaren Ressourcen ab. Es werden jedoch 4 MB bzw. 32 MB als Ausgangspunkt empfohlen.

Hinweis: Dies sind "pro Verbindung" -Werte zwischen read_buffer_size, read_rnd_buffer_size und einigen anderen, was bedeutet, dass dieser Wert möglicherweise für jede Verbindung benötigt wird. Berücksichtigen Sie also Ihre Last und die verfügbare Ressource, wenn Sie diese Parameter einstellen. Beispielsweise wird sort_buffer_size nur zugewiesen, wenn MySQL eine Sortierung durchführen muss. Hinweis: Achten Sie darauf, dass Ihnen nicht der Speicher ausgeht.

Wenn Sie viele Verbindungen hergestellt haben (dh eine Website ohne dauerhafte Verbindungen), können Sie die Leistung verbessern, indem Sie thread_cache_size auf einen Wert ungleich Null setzen. 16 ist ein guter Wert für den Anfang. Erhöhen Sie den Wert, bis Ihre threads_created nicht mehr sehr schnell wachsen.

PRIMÄRSCHLÜSSEL:

Es kann nur eine AUTO_INCREMENT-Spalte pro Tabelle geben, sie muss indiziert sein und darf keinen DEFAULT-Wert haben

KEY ist normalerweise ein Synonym für INDEX. Das Schlüsselattribut PRIMARY KEY kann auch als nur KEY angegeben werden, wenn es in einer Spaltendefinition angegeben wird. Dies wurde aus Gründen der Kompatibilität mit anderen Datenbanksystemen implementiert.

Ein PRIMARY KEY ist ein eindeutiger Index, bei dem alle Schlüsselspalten als NOT NULL definiert werden müssen

Wenn ein PRIMARY KEY- oder UNIQUE-Index nur aus einer Spalte mit einem Integer-Typ besteht, können Sie die Spalte in SELECT-Anweisungen auch als "_rowid" bezeichnen.

In MySQL lautet der Name eines PRIMARY KEY PRIMARY

Derzeit unterstützen nur InnoDB-Tabellen (v5.1?) Fremdschlüssel.

Normalerweise erstellen Sie alle Indizes, die Sie beim Erstellen von Tabellen benötigen. Jede Spalte, die als PRIMARY KEY, KEY, UNIQUE oder INDEX deklariert ist, wird indiziert.

NULL bedeutet "keinen Wert haben". Zum Testen auf NULL können Sie keine arithmetischen Vergleichsoperatoren wie =, <oder <> verwenden. Verwenden Sie stattdessen die Operatoren IS NULL und IS NOT NULL:

NO_AUTO_VALUE_ON_ZERO unterdrückt das automatische Inkrement für 0, sodass nur NULL die nächste Sequenznummer generiert. Dieser Modus kann nützlich sein, wenn 0 in der Spalte AUTO_INCREMENT einer Tabelle gespeichert wurde. (Das Speichern von 0 wird übrigens nicht empfohlen.)

So ändern Sie den Wert des Zählers AUTO_INCREMENT, der für neue Zeilen verwendet werden soll:

ALTER TABLE mytable AUTO_INCREMENT = value; 

oder SET INSERT_ID = Wert;

Sofern nicht anders angegeben, beginnt der Wert mit: 1000000 oder geben Sie ihn folgendermaßen an:

...) ENGINE = MyISAM DEFAULT CHARSET = latin1 AUTO_INCREMENT = 1

ZEITSTEMPEL:

Werte für TIMESTAMP-Spalten werden zum Speichern von der aktuellen Zeitzone in UTC und zum Abrufen von UTC in die aktuelle Zeitzone konvertiert.

http://dev.mysql.com/doc/refman/5.1/de/timestamp.html Für eine TIMESTAMP-Spalte in einer Tabelle können Sie den aktuellen Zeitstempel als Standardwert und den Wert für die automatische Aktualisierung zuweisen.

Bei der Verwendung eines dieser Typen in einer WHERE-Klausel ist es am besten, WHERE datecolumn = FROM_UNIXTIME (1057941242) und nicht WHERE UNIX_TIMESTAMP (datecolumn) = 1057941242 zu verwenden. Letzteres nutzt keinen Index auf dieser Spalte.

http://dev.mysql.com/doc/refman/5.1/en/date-and-time-functions.html

 UNIX_TIMESTAMP() 
 FROM_UNIXTIME() 
 UTC_DATE()
 UTC_TIME()
 UTC_TIMESTAMP()

Wenn Sie eine Datums- und Uhrzeitangabe in MySQL in einen Unix-Zeitstempel konvertieren:
Und dann 24 Stunden hinzufügen:
Und dann wieder in eine Datumszeit konvertieren, verliert sie auf magische Weise eine Stunde!

Hier ist was passiert. Bei der Konvertierung des Unix-Zeitstempels zurück in eine Datumszeit wird die Zeitzone berücksichtigt, und es kommt vor, dass wir zwischen dem 28. und 29. Oktober 2006 die Sommerzeit verloren haben und eine Stunde verloren haben.

Ab MySQL 4.1.3 geben die Funktionen CURRENT_TIMESTAMP (), CURRENT_TIME (), CURRENT_DATE () und FROM_UNIXTIME () Werte in der aktuellen Zeitzone der Verbindung zurück , die als Wert der Systemvariablen time_zone verfügbar ist. Außerdem geht UNIX_TIMESTAMP () davon aus, dass das Argument ein Datum / Uhrzeit-Wert in der aktuellen Zeitzone ist.

Die aktuelle Zeitzoneneinstellung wirkt sich nicht auf Werte aus, die von Funktionen wie UTC_TIMESTAMP () angezeigt werden, oder auf Werte in den Spalten DATE, TIME oder DATETIME.

HINWEIS: NUR BEI UPDATE aktualisiert die DateTime, wenn ein Feld geändert wird. Wenn ein UPDATE dazu führt, dass keine Felder geändert werden, wird die DateTime NICHT aktualisiert!

Zusätzlich ist der erste TIMESTAMP standardmäßig immer AUTOUPDATE, auch wenn er nicht angegeben ist

Wenn ich mit Datumsangaben arbeite, gehe ich fast immer zu Julian Date über, da Datenmathematik aus dem gleichen Grund eine einfache Angelegenheit ist, Ganzzahlen und Sekunden seit Mitternacht zu addieren oder zu subtrahieren. Es ist selten, dass ich eine zeitliche Auflösung mit einer feineren Granularität als Sekunden benötige.

Beide können als 4-Byte-Ganzzahl gespeichert werden, und wenn der Speicherplatz sehr knapp ist, können sie als vorzeichenlose Ganzzahl, die bis etwa 2106 gültig ist, in UNIX-Zeit (Sekunden seit der Epoche 01.01.1970) kombiniert werden als:

Sekunden in 24 Stunden = 86400

'Signed Integer max val = 2.147.483.647 - kann 68 Jahre von Sekunden halten

'Unsigned Integer max val = 4,294,967,295 - kann 136 Jahre von Sekunden halten

Binäres Protokoll:

Mit MySQL 4.1 wurde ein Binärprotokoll eingeführt, mit dem Datenwerte ohne Zeichenfolge im nativen Format gesendet und zurückgegeben werden können, ohne dass sie in das Zeichenfolgenformat konvertiert werden müssen. (Sehr hilfreich)

Außerdem ist mysql_real_query () schneller als mysql_query (), da strlen () nicht aufgerufen wird, um die Anweisungszeichenfolge zu bearbeiten.

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html Das Binärprotokoll unterstützt serverseitig vorbereitete Anweisungen und ermöglicht die Übertragung von Datenwerten im nativen Format. Das Binärprotokoll wurde in früheren Versionen von MySQL 4.1 ziemlich überarbeitet.

Mit dem Makro IS_NUM () können Sie testen, ob ein Feld einen numerischen Typ hat. Übergeben Sie den Typwert an IS_NUM () und er wird als TRUE ausgewertet, wenn das Feld numerisch ist:

Eine Sache zu beachten ist , dass binäre Daten CAN innerhalb einer regelmäßigen Abfrage gesendet, wenn Sie es entkommen und erinnern MySQL erfordert nur , dass Backslash und die Anführungszeichen maskiert werden. Das ist also eine sehr einfache Möglichkeit, kürzere Binärzeichenfolgen wie beispielsweise verschlüsselte / gesalzene Passwörter einzufügen.

Master Server:

http://www.experts-exchange.com/Database/MySQL/Q_22967482.html

http://www.databasejournal.com/features/mysql/article.php/10897_3355201_2

GRANT REPLICATION SLAVE ON . to Slave_Benutzer IDENTIFIZIERT DURCH 'Slave_Password'

#Master Binary Logging Config  STATEMENT causes replication 
              to be statement-based -  default

log-bin=Mike
binlog-format=STATEMENT
server-id=1            
max_binlog_size = 10M
expire_logs_days = 120    


#Slave Config
master-host=master-hostname
master-user=slave-user
master-password=slave-password
server-id=2

Die binäre Protokolldatei muss lauten:

http://dev.mysql.com/doc/refman/5.0/en/binary-log.html

http://www.mydigitallife.info/2007/10/06/how-to-read-mysql-binary-log-files-binlog-with-mysqlbinlog/

http://dev.mysql.com/doc/refman/5.1/en/mysqlbinlog.html

http://dev.mysql.com/doc/refman/5.0/en/binary-log.html

http://dev.mysql.com/doc/refman/5.1/en/binary-log-setting.html

Sie können alle binären Protokolldateien mit der Anweisung RESET MASTER oder eine Teilmenge davon mit PURGE MASTER löschen

--result-file = binlog.txt TrustedFriend-bin.000030

Normalisierung:

http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html

UDF-Funktionen

http://www.koders.com/cpp/fid10666379322B54AD41AEB0E4100D87C8CDDF1D8C.aspx

http://souptonuts.sourceforge.net/readme_mysql.htm

Datentypen:

http://dev.mysql.com/doc/refman/5.1/en/storage-requirements.html

http://www.informit.com/articles/article.aspx?p=1238838&seqNum=2

http://bitfilm.net/2008/03/24/saving-bytes-efficient-data-storage-mysql-part-1/

Zu beachten ist, dass mySQL in einer gemischten Tabelle mit CHAR und VARCHAR die CHARs in VARCHARs ändert

RecNum integer_type UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (RecNum)

MySQL repräsentiert immer Daten mit dem ersten Jahr gemäß den Standardspezifikationen von SQL und ISO 8601

Sonstiges:

Das Deaktivieren einiger MySQl-Funktionen führt zu kleineren Datendateien und einem schnelleren Zugriff. Beispielsweise:

--datadir gibt das Datenverzeichnis und an

--skip-innodb deaktiviert die inno-Option und spart Ihnen 10-20 Millionen

Mehr hier http://dev.mysql.com/tech-resources/articles/mysql-c-api.html

Laden Sie Kapitel 7 - Kostenlos herunter

InnoDB ist eine Transaktion, aber damit verbunden ist ein Leistungsaufwand. Ich habe festgestellt, dass MyISAM-Tabellen für 90% meiner Projekte ausreichen. Nicht transaktionssichere Tabellen (MyISAM) haben mehrere eigene Vorteile, die alle auftreten, weil:

Es gibt keinen Transaktionsaufwand:

Viel schneller

Geringerer Speicherplatzbedarf

Für die Durchführung von Updates ist weniger Speicher erforderlich

Jede MyISAM-Tabelle wird in drei Dateien auf der Festplatte gespeichert. Die Dateien haben Namen, die mit dem Tabellennamen beginnen, und eine Erweiterung, die den Dateityp angibt. Eine .frm-Datei speichert das Tabellenformat. Die Datendatei hat die Erweiterung .MYD (MYData). Die Indexdatei hat die Erweiterung .MYI (MYIndex).

Diese Dateien können an einen intakten Speicherort kopiert werden, ohne die zeitaufwändige MySQL Administrators Backup-Funktion zu verwenden (ebenso die Wiederherstellung).

Der Trick besteht darin, eine Kopie dieser Dateien zu erstellen und dann die Tabelle zu löschen. Wenn Sie die Dateien zurücklegen, erkennt MySQl sie und aktualisiert die Tabellenverfolgung.

Wenn Sie sichern / wiederherstellen müssen,

Das Wiederherstellen einer Sicherung oder das Importieren aus einer vorhandenen Speicherauszugsdatei kann abhängig von der Anzahl der Indizes und Primärschlüssel, die Sie in jeder Tabelle haben, lange dauern. Sie können diesen Vorgang erheblich beschleunigen, indem Sie Ihre ursprüngliche Speicherauszugsdatei ändern, indem Sie sie wie folgt umgeben:

SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS=0;

.. your dump file ..

SET FOREIGN_KEY_CHECKS = 1;
COMMIT;
SET AUTOCOMMIT = 1;

Fügen Sie den SQL-Befehl SET AUTOCOMMIT = 0 hinzu, um die Geschwindigkeit des Neuladens erheblich zu erhöhen. am Anfang der Dump-Datei und fügen Sie das COMMIT hinzu; Befehl bis zum Ende.

Standardmäßig ist die automatische Festschreibung aktiviert. Dies bedeutet, dass jeder Einfügebefehl in der Speicherauszugsdatei als separate Transaktion behandelt und vor dem nächsten Start auf die Festplatte geschrieben wird. Wenn Sie diese Befehle nicht hinzufügen, kann das erneute Laden einer großen Datenbank in InnoDB viele Stunden dauern ...

Die maximale Größe einer Zeile in einer MySQL-Tabelle beträgt 65.535 Byte

Die effektive maximale Länge eines VARCHAR in MySQL 5.0.3 und höher = maximale Zeilengröße (65.535 Byte)

VARCHAR-Werte werden beim Speichern nicht aufgefüllt. Nachgestellte Leerzeichen bleiben erhalten, wenn Werte gemäß Standard-SQL gespeichert und abgerufen werden.

CHAR- und VARCHAR-Werte in MySQL werden unabhängig von nachgestellten Leerzeichen verglichen.

Die Verwendung von CHAR beschleunigt Ihren Zugriff nur, wenn der gesamte Datensatz eine feste Größe hat. Das heißt, wenn Sie ein Objekt mit variabler Größe verwenden, können Sie auch alle Objekte mit variabler Größe erstellen. Sie gewinnen keine Geschwindigkeit, wenn Sie ein CHAR in einer Tabelle verwenden, die auch ein VARCHAR enthält.

Das VARCHAR-Limit von 255 Zeichen wurde ab MySQL 5.0.3 auf 65535 Zeichen erhöht

Volltextsuchen werden nur für MyISAM-Tabellen unterstützt.

http://dev.mysql.com/doc/refman/5.0/en/fulltext-search.html

BLOB-Spalten haben keinen Zeichensatz, und Sortierung und Vergleich basieren auf den numerischen Werten der Bytes in Spaltenwerten

Wenn der strikte SQL-Modus nicht aktiviert ist und Sie einer BLOB- oder TEXT-Spalte einen Wert zuweisen, der die maximale Länge der Spalte überschreitet, wird der Wert passend abgeschnitten und eine Warnung generiert.

Nützliche Befehle:

Überprüfen Sie den strengen Modus: SELECT @@ global.sql_mode;

Strengen Modus ausschalten:

SET @@ global.sql_mode = '';

SET @@ global.sql_mode = 'MYSQL40'

oder entfernen: sql-mode = "STRICT_TRANS_TABLES, ...

SHOW COLUMNS FROM mytable

SELECT max (namecount) AS virtualcolumnFROM mytable ORDER BY virtualcolumn

http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-fields.html

http://dev.mysql.com/doc/refman/5.1/de/information-functions.html#function_last-insert-id last_insert_id ()

Ruft die PK der letzten Zeile ab, die in den aktuellen Thread eingefügt wurde. max (pkcolname) Erhält die letzte PK insgesamt.

Hinweis: Wenn die Tabelle leer ist, gibt max (pkcolname) 1 zurück. Mysql_insert_id () konvertiert den Rückgabetyp der nativen MySQL C-API-Funktion mysql_insert_id () in einen Long-Typ (in PHP int genannt).

Wenn Ihre AUTO_INCREMENT-Spalte den Spaltentyp BIGINT hat, ist der von mysql_insert_id () zurückgegebene Wert falsch. Verwenden Sie stattdessen die interne MySQL SQL-Funktion LAST_INSERT_ID () in einer SQL-Abfrage.

http://dev.mysql.com/doc/refman/5.0/de/information-functions.html#function_last-insert-id

Nur ein Hinweis: Wenn Sie versuchen, Daten in eine Tabelle einzufügen, wird folgende Fehlermeldung angezeigt:

Unknown column the first bit of data what you want to put into the table in field list

mit so etwas wie

INSERT INTO table (this, that) VALUES ($this, $that)

Das liegt daran, dass Sie keine Apostrophe um die Werte haben, die Sie in die Tabelle einfügen möchten. Sie sollten Ihren Code also ändern in:

INSERT INTO table (this, that) VALUES ('$this', '$that') 

daran erinnern, dass `` verwendet werden, um MySQL-Felder, Datenbanken oder Tabellen zu definieren, keine Werte;)

Verbindung zum Server während der Abfrage verloren:

http://dev.mysql.com/doc/refman/5.1/en/gone-away.html

http://dev.mysql.com/doc/refman/5.1/en/packet-too-large.html

http://dev.mysql.com/doc/refman/5.0/en/server-parameters.html

http://dev.mysql.com/doc/refman/5.1/en/show-variables.html

http://dev.mysql.com/doc/refman/5.1/en/option-files.html

http://dev.mysql.com/doc/refman/5.1/en/error-log.html

Abfragen optimieren

http://www.artfulsoftware.com/infotree/queries.php?&bw=1313

Nun, das sollte ausreichen, um den Bonus zu verdienen, den ich denke ... Die Früchte vieler Stunden und vieler Projekte mit einer großartigen kostenlosen Datenbank. Ich entwickle Anwendungsdatenserver auf Windows-Plattformen hauptsächlich mit MySQL. Das schlimmste Durcheinander, das ich beseitigen musste, war

Der ultimative Alptraum für MySQL-Legacy-Datenbanken

Dies erforderte eine Reihe von Anwendungen, um die Tabellen mit vielen der hier genannten Tricks zu etwas Nützlichem zu verarbeiten.

Wenn Sie dies erstaunlich hilfreich fanden, drücken Sie Ihren Dank aus, indem Sie es abstimmen.

Lesen Sie auch meine anderen Artikel und Whitepaper unter: www.coastrd.com


22

Eine der nicht so versteckten Funktionen von MySQL ist, dass es nicht wirklich gut darin ist, SQL-kompatibel zu sein, also nicht wirklich Fehler, aber mehr Fallstricke ... :-)


Andere wissen, dass diese Liste beim Wechsel von MSSQL zu MySQL hilfreich war. Prost Mat.
GateKiller

Viele dieser Fallstricke stammen aus früheren Versionen von MySQL.
jmucchiello

Zum einen glaube ich nicht, dass es jemals möglich sein wird, einen NULL-Wert in ein Zeitstempelfeld einzufügen.
Matte

3
MySQL ist nicht besonders schlecht darin, SQL-kompatibel zu sein als viele andere Datenbanken. Solange Sie sich an eine vernünftige Teilmenge von SQL halten, können Sie im Allgemeinen die Fallstricke vermeiden - was mehr ist, als z. Oracle berüchtigte leere Nullzeichenfolgen.
Bobince

1
Sie können einige der Fallstricke deaktivierenSET SESSION sql_mode='ANSI';
Kornel

21

Ein Befehl, um herauszufinden, welche Tabellen sich derzeit im Cache befinden:

mysql> SHOW open TABLES FROM test;
+----------+-------+--------+-------------+
| DATABASE | TABLE | In_use | Name_locked |
+----------+-------+--------+-------------+
| test     | a     |      3 |           0 |
+----------+-------+--------+-------------+
1 row IN SET (0.00 sec)

(Aus dem MySQL Performance Blog )


15

Ein Befehl, um herauszufinden, wer was tut:

mysql> show processlist;
show processlist;
+----+-------------+-----------------+------+---------+------+----------------------------------+------------------+
| Id | User        | Host            | db   | Command | Time | State                            | Info             |
+----+-------------+-----------------+------+---------+------+----------------------------------+------------------+
|  1 | root        | localhost:32893 | NULL | Sleep   |    0 |                                  | NULL             |
|  5 | system user |                 | NULL | Connect |   98 | Waiting for master to send event | NULL             |
|  6 | system user |                 | NULL | Connect | 5018 | Reading event from the relay log | NULL             |
+-----+------+-----------+---------+---------+-------+-------+------------------+
3 rows in set (0.00 sec) 

Und Sie können einen Prozess beenden mit:

mysql>kill 5 

5
SHOW FULL PROCESSLIST auch, wenn die Abfragen nicht abgeschnitten werden sollen.
Greg

11

Besonders gut gefällt mir die integrierte Unterstützung von MySQL für inet_ntoa()und inet_aton(). Dies macht den Umgang mit IP-Adressen in Tabellen sehr einfach (zumindest solange es sich nur um IPv4-Adressen handelt!).


2
PostgreSQL hat einen sehr schönen Inet-Typ, der IPv4 und IPv6 sehr gut handhabt :-)
Mat

Früher mochte ich sie auch, aber es ist noch besser, sie überhaupt nicht benutzen zu müssen. +1 für Postgres.
Kornel

11

Ich liebe on duplicate key(AKA upsert, merge) für alle Arten von Zählern, die träge erstellt wurden:

insert into occurances(word,count) values('foo',1),('bar',1) 
  on duplicate key cnt=cnt+1

Sie können viele Zeilen in eine Abfrage einfügen und sofort den doppelten Index für jede der Zeilen verarbeiten.


10

Wieder - nicht wirklich versteckte Funktionen, aber wirklich praktisch:

Feature

Einfach DDL holen:

SHOW CREATE TABLE CountryLanguage

Ausgabe:

CountryLanguage | CREATE TABLE countrylanguage (
  CountryCode char(3) NOT NULL DEFAULT '',
  Language char(30) NOT NULL DEFAULT '',
  IsOfficial enum('T','F') NOT NULL DEFAULT 'F',
  Percentage float(4,1) NOT NULL DEFAULT '0.0',
  PRIMARY KEY (CountryCode,Language)
) ENGINE=MyISAM DEFAULT CHARSET=latin1

Feature: Aggregatfunktion GROUP_CONCAT () Erstellt eine verkettete Zeichenfolge ihrer Argumente pro Detail und aggregiert durch Verketten dieser pro Gruppe.

Beispiel 1: einfach

SELECT   CountryCode
,        GROUP_CONCAT(Language) AS List
FROM     CountryLanguage
GROUP BY CountryCode             

Ausgabe:

+-------------+------------------------------------+
| CountryCode | List                               |
+-------------+------------------------------------+
| ABW         | Dutch,English,Papiamento,Spanish   |
. ...         . ...                                .
| ZWE         | English,Ndebele,Nyanja,Shona       |
+-------------+------------------------------------+

Beispiel 2: mehrere Argumente

SELECT   CountryCode
,        GROUP_CONCAT(
             Language
,            IF(IsOfficial='T', ' (Official)', '')
         )               AS List
FROM     CountryLanguage
GROUP BY CountryCode

Ausgabe:

+-------------+---------------------------------------------+
| CountryCode | List                                        |
+-------------+---------------------------------------------+
| ABW         | Dutch (Official),English,Papiamento,Spanish |
. ...         . ...                                         .
| ZWE         | English (Official),Ndebele,Nyanja,Shona     |
+-------------+---------------------------------------------+

Beispiel 3: Verwenden eines benutzerdefinierten Trennzeichens

SELECT   CountryCode
,        GROUP_CONCAT(Language SEPARATOR ' and ') AS List
FROM     CountryLanguage
GROUP BY CountryCode

Ausgabe:

+-------------+----------------------------------------------+
| CountryCode | List                                         |
+-------------+----------------------------------------------+
| ABW         | Dutch and English and Papiamento and Spanish |
. ...         . ...                                          .
| ZWE         | English and Ndebele and Nyanja and Shona     |
+-------------+----------------------------------------------+

Beispiel 4: Steuern der Reihenfolge der Listenelemente

SELECT   CountryCode
,        GROUP_CONCAT(
         Language
         ORDER BY CASE IsOfficial WHEN 'T' THEN 1 ELSE 2 END DESC
         ,        Language
         )               AS List
FROM     CountryLanguage
GROUP BY CountryCode

Ausgabe:

+-------------+------------------------------------+
| CountryCode | List                               |
+-------------+------------------------------------+
| ABW         | English,Papiamento,Spanish,Dutch,  |
. ...         . ...                                .
| ZWE         | Ndebele,Nyanja,Shona,English       |
+-------------+------------------------------------+

Feature: COUNT (DISTINCT) mit mehreren Ausdrücken

Sie können mehrere Ausdrücke in einem COUNT-Ausdruck (DISTINCT ...) verwenden, um die Anzahl der Kombinationen zu zählen.

SELECT COUNT(DISTINCT CountryCode, Language) FROM CountryLanguage

Feature / Gotcha: Es ist nicht erforderlich, nicht aggregierte Ausdrücke in die GROUP BY-Liste aufzunehmen

Die meisten RDBMS erzwingen ein SQL92-kompatibles GROUP BY, bei dem alle nicht aggregierten Ausdrücke in der SELECT-Liste im GROUP BY angezeigt werden müssen. In diesen RDBMS-es ist diese Aussage:

SELECT     Country.Code, Country.Continent, COUNT(CountryLanguage.Language)
FROM       CountryLanguage 
INNER JOIN Country 
ON         CountryLanguage.CountryCode = Country.Code
GROUP BY   Country.Code

ist ungültig, da die SELECT-Liste die nicht aggregierte Spalte Country.Continent enthält, die nicht in der GROUP BY-Liste angezeigt wird. In diesen RDBMS-es müssen Sie entweder die GROUP BY-Liste zum Lesen ändern

GROUP BY   Country.Code, Country.Continent

oder Sie müssen beispielsweise Country.Continent ein unsinniges Aggregat hinzufügen

SELECT     Country.Code, MAX(Country.Continent), COUNT(CountryLanguage.Language)

Nun ist die Sache, logischerweise gibt es nichts, was verlangt, dass Country.Continent aggreagiert wird. Siehe Country.Code ist der Primärschlüssel der Country-Tabelle. Country.Continent ist auch eine Spalte aus der Country-Tabelle und hängt daher per Definition funktional vom Primärschlüssel Country.Code ab. Es muss also genau einen Wert in Country.Continent für jeden einzelnen Country.Code geben. Wenn Sie dies erkennen, ist es nicht sinnvoll, es zu aggregieren (es gibt nur einen Wert, richtig) oder danach zu gruppieren (da dies das Ergebnis nicht eindeutiger macht, da Sie bereits nach on gruppieren das pk)

Wie auch immer - Mit MySQL können Sie nicht aggregierte Spalten in die SELECT-Liste aufnehmen, ohne dass Sie sie auch der GROUP BY-Klausel hinzufügen müssen.

Das Problem dabei ist, dass MySQL Sie nicht schützt, falls Sie zufällig eine nicht aggregierte Spalte verwenden. Also eine Abfrage wie diese:

SELECT     Country.Code, COUNT(CountryLanguage.Language), CountryLanguage.Percentage
FROM       CountryLanguage 
INNER JOIN Country 
ON         CountryLanguage.CountryCode = Country.Code
GROUP BY   Country.Code

Wird ohne Beanstandung ausgeführt, aber die Spalte CountryLanguage.Percentage enthält Unsinn (dh von allen Sprachprozentsätzen wird einer der verfügbaren Werte für den Prozentsatz zufällig oder zumindest außerhalb Ihrer Kontrolle ausgewählt.

Siehe: Gruppe nach Mythen entlarven


Das Zulassen von Spalten, die nicht in der Gruppe deklariert sind, ist eine meiner am wenigsten bevorzugten Funktionen von Oracle. Es ist ein großes Problem, wenn Sie an Oracle gewöhnt sind - Sie können nur die Abfrage ausführen, die Ergebnisse sehen richtig aus, aber dann stellen Sie fest, dass es nicht das tut, was Sie dachten.
Mbafford

7

Der Befehl "Pager" im Client

Wenn Sie beispielsweise 10.000 Zeilen in Ihrem Ergebnis haben und diese anzeigen möchten (Dies setzt die verfügbaren Befehle "less" und "tee" voraus, was normalerweise unter Linux der Fall ist; in Windows YMMV.)

pager less
select lots_of_stuff FROM tbl WHERE clause_which_matches_10k_rows;

Und Sie erhalten sie im "weniger" -Dateibetrachter, damit Sie sie gut durchblättern, suchen usw. können.

Ebenfalls

pager tee myfile.txt
select a_few_things FROM tbl WHERE i_want_to_save_output_to_a_file;

Schreibt bequem in eine Datei.


Leider wird unter Windows die Pager-Option selbst nicht unterstützt, auch wenn "less" und "tee" vorhanden sind. sowieso nicht leicht
Berry Tsakala

6

Einige Dinge, die Sie vielleicht interessant finden:

<query>\G -- \G in the CLI instead of the ; will show one column per row
explain <query>; -- this will show the execution plan for the query


3

Hier sind einige meiner Tipps - ich habe darüber in meinem Blog gebloggt ( Link )

  1. Sie müssen das @ -Zeichen nicht verwenden, wenn Sie Variablen deklarieren.
  2. Sie müssen ein Trennzeichen verwenden (der Standardwert ist ';'), um das Ende einer Anweisung abzugrenzen - Link
  3. Wenn Sie versuchen, Daten zwischen MS-SQL 2005 und mySQL zu verschieben, müssen Sie einige Schritte ausführen - Link
  4. Übereinstimmungen zwischen Groß- und Kleinschreibung in mySQL - Link

3

Wenn Sie mit großen und / oder hohen Transaktions-InnoDb-Datenbanken arbeiten, lernen und verstehen Sie den MySQL-Leistungsblog "SHOW INNODB STATUS" , der zu Ihrem Freund wird.


3

Wenn Sie cmdline Mysq verwenden, können Sie mit der Befehlszeile interagieren (auf Linux-Computern - nicht sicher, ob unter Windows ein gleichwertiger Effekt vorliegt), indem Sie das Schrei- / Ausrufezeichen verwenden. Beispielsweise:

\! cat file1.sql

zeigt den Code für file1.sql an. Verwenden Sie die Tee-Funktion, um Ihre Anweisung und Abfrage in einer Datei zu speichern

\T filename

Um dies auszuschalten, verwenden Sie \ t

Verwenden Sie zum Ausführen eines bereits gespeicherten Skripts "Quellendateiname". Die normale Alternative besteht natürlich darin, den Skriptnamen einzugeben, wenn Sie MySQL über die Befehlszeile starten:

    mysql -u root -p < case1.sql

Hoffe, das nützt jemandem!

Bearbeiten: Ich habe mich gerade an eine andere erinnert - wenn Sie MySQL über die Befehlszeile aufrufen, können Sie den Schalter -t verwenden, damit die Ausgabe im Tabellenformat erfolgt - ein wahrer Segen bei einigen Abfragen (obwohl das Beenden von Abfragen mit \ G, wie an anderer Stelle hier erwähnt, natürlich auch der Fall ist hilfreich in dieser Hinsicht). Viel mehr über verschiedene Schalter Command Line Tool

Ich habe gerade eine gute Möglichkeit gefunden, die Reihenfolge einer Sortierung zu ändern (normalerweise Groß- und Kleinschreibung verwenden ...). Wenn Sie die Reihenfolge einer Sortierung ändern möchten (möglicherweise nach 1, 4, 3, 2 anstatt nach 1, 2, 3 sortieren, 4) Sie können die Feldfunktion innerhalb der Order by-Klausel verwenden. Beispielsweise

Nach Feld sortieren (sort_field, 1,4,3,2)


3

Ich denke nicht, dass dies MySQL-spezifisch ist, aber für mich aufschlussreich:

Anstatt zu schreiben

WHERE (x.id > y.id) OR (x.id = y.id AND x.f2 > y.f2) 

Du kannst einfach schreiben

WHERE (x.id, x.f2) > (y.id, y.f2)

Das ist wirklich cool, aber was wären einige Anwendungsfälle dafür?
MangoDrunk

Dies kann nützlich sein, um alle Datensätze zu finden, die größer als ein bestimmter Datensatz sind.
Fantius

2

mysqlsla - Eines der am häufigsten verwendeten Tools zur Analyse langsamer Abfrageprotokolle. Sie können die 10 schlechtesten Abfragen sehen, seit Sie zuletzt langsame Abfrageprotokolle eingeführt haben. Außerdem können Sie feststellen, wie oft die BAD-Abfrage ausgelöst wurde und wie viel Zeit insgesamt auf dem Server benötigt wurde.


2

Eigentlich dokumentiert , aber sehr nervig: automatische Konvertierungen für falsche Daten und andere falsche Eingaben.

Vor MySQL 5.0.2 vergibt MySQL illegale oder unzulässige Datenwerte und zwingt sie zur Dateneingabe zu legalen Werten. In MySQL 5.0.2 und höher bleibt dies das Standardverhalten. Sie können jedoch den Server-SQL-Modus ändern, um eine traditionellere Behandlung fehlerhafter Werte auszuwählen, sodass der Server sie ablehnt und die Anweisung abbricht, in der sie auftreten.

Was Datumsangaben betrifft: Manchmal haben Sie "Glück", wenn MySQL die Eingabe nicht an nahegelegene gültige Datumsangaben anpasst, sondern diese als 0000-00-00per Definition ungültig speichert . Selbst dann wollten Sie vielleicht, dass MySQL fehlschlägt, anstatt diesen Wert stillschweigend für Sie zu speichern.



1

InnoDB speichert standardmäßig alle Tabellen in einem globalen Tabellenbereich, der niemals verkleinert wird .

Sie können verwenden innodb_file_per_table , um jede Tabelle in einem separaten Tabellenbereich abzulegen, der gelöscht wird, wenn Sie die Tabelle oder Datenbank löschen.

Planen Sie dies im Voraus, da Sie die Datenbank sichern und wiederherstellen müssen, um andernfalls Speicherplatz zurückzugewinnen.

Verwenden von Tabellenbereichen pro Tabelle


1

Wenn Sie den leeren Zeichenfolgenwert "" in die Spalte datetime einfügen, behält MySQL den Wert 00/00/0000 00:00:00 bei. Im Gegensatz zu Oracle, bei dem der Nullwert gespeichert wird.


1

Bei meinen Benchmarks mit großen Datenmengen und DATETIME-Feldern ist diese Abfrage immer langsamer:

SELECT * FROM mytable
WHERE date(date_colum) BETWEEN '2011-01-01' AND ''2011-03-03';

Als dieser Ansatz:

SELECT * FROM mytable
WHERE date_column BETWEEN '2011-01-01 00:00:00' AND '2011-03-03 23:59:59'
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.