Ukryte funkcje MySQL

101

Pracuję z Microsoft SQL Server od wielu lat, ale dopiero niedawno zacząłem używać MySQL z moimi aplikacjami internetowymi i jestem głodny wiedzy.

Kontynuując długą linię pytań dotyczących „ukrytych funkcji” , chciałbym poznać wszelkie ukryte lub przydatne funkcje MySQL, które, mam nadzieję, poprawią moją wiedzę na temat tej bazy danych typu open source.

GateKiller
źródło

Odpowiedzi:

161

Odkąd wyznaczyłeś nagrodę, podzielę się moimi ciężko zdobytymi sekretami ...

Ogólnie rzecz biorąc, wszystkie SQL, które dostroiłem dzisiaj, wymagały użycia pod-zapytań. Pochodząc ze świata baz danych Oracle, rzeczy, które uważałem za oczywiste, nie działały tak samo z MySQL. Po przeczytaniu informacji o strojeniu MySQL dochodzę do wniosku, że MySQL stoi za Oracle pod względem optymalizacji zapytań.

Podczas gdy proste zapytania wymagane dla większości aplikacji B2C mogą dobrze działać w przypadku MySQL, większość zapytań typu zagregowanego raportowania potrzebnych do raportowania inteligencji wydaje się wymagać sporo planowania i reorganizacji zapytań SQL, tak aby MySQL wykonywał je szybciej.

Administracja:

max_connectionsto liczba jednoczesnych połączeń. Wartość domyślna to 100 połączeń (151 od wersji 5.0) - bardzo mała.

Uwaga:

połączenia zajmują pamięć, a system operacyjny może nie być w stanie obsłużyć wielu połączeń.

Pliki binarne MySQL dla Linux / x86 pozwalają na posiadanie do 4096 jednoczesnych połączeń, ale pliki binarne skompilowane samodzielnie często mają mniejszy limit.

Ustaw table_cache tak, aby odpowiadała liczbie otwartych tabel i jednoczesnych połączeń. Obserwuj wartość open_tables, a jeśli szybko rośnie, musisz zwiększyć jego rozmiar.

Uwaga:

Dwa poprzednie parametry mogą wymagać wielu otwartych plików. 20 + max_connections + table_cache * 2 to dobre oszacowanie tego, czego potrzebujesz. MySQL w systemie Linux ma opcję open_file_limit, ustaw ten limit.

Jeśli masz złożone zapytania, sort_buffer_size i tmp_table_size będą prawdopodobnie bardzo ważne. Wartości będą zależeć od złożoności zapytania i dostępnych zasobów, ale odpowiednio 4 MB i 32 MB są zalecanymi punktami początkowymi.

Uwaga: są to wartości „na połączenie”, między innymi read_buffer_size, read_rnd_buffer_size i kilka innych, co oznacza, że ​​ta wartość może być potrzebna dla każdego połączenia. Dlatego podczas ustawiania tych parametrów należy wziąć pod uwagę obciążenie i dostępne zasoby. Na przykład sort_buffer_size jest przydzielany tylko wtedy, gdy MySQL musi wykonać sortowanie. Uwaga: uważaj, aby nie zabrakło pamięci.

Jeśli masz ustanowionych wiele połączeń (np. Witryna internetowa bez trwałych połączeń), możesz poprawić wydajność, ustawiając wartość thread_cache_size na wartość niezerową. 16 to dobra wartość na początek. Zwiększaj wartość, dopóki twoje wątki_created nie będą rosły bardzo szybko.

KLUCZ PODSTAWOWY:

W tabeli może istnieć tylko jedna kolumna AUTO_INCREMENT, musi być zindeksowana i nie może mieć wartości DEFAULT

KEY jest zwykle synonimem INDEX. Atrybut klucza PRIMARY KEY można również określić jako po prostu KEY, jeśli jest podany w definicji kolumny. Zostało to zaimplementowane w celu zapewnienia zgodności z innymi systemami baz danych.

KLUCZ PODSTAWOWY to unikalny indeks, w którym wszystkie kolumny kluczy muszą być zdefiniowane jako NIE NULL

Jeśli indeks PRIMARY KEY lub UNIQUE składa się tylko z jednej kolumny o typie całkowitym, w instrukcjach SELECT można również odwoływać się do kolumny jako „_rowid”.

W MySQL nazwa KLUCZA PODSTAWOWEGO to PRIMARY

Obecnie tylko tabele InnoDB (v5.1?) Obsługują klucze obce.

Zwykle wszystkie indeksy są potrzebne podczas tworzenia tabel. Każda kolumna zadeklarowana jako PRIMARY KEY, KEY, UNIQUE lub INDEX będzie indeksowana.

NULL oznacza „brak wartości”. Aby przetestować wartość NULL, nie można użyć arytmetycznych operatorów porównania, takich jak =, <lub <>. Zamiast tego użyj operatorów IS NULL i IS NOT NULL:

NO_AUTO_VALUE_ON_ZERO wstrzymuje automatyczne zwiększanie wartości 0, tak że tylko NULL generuje następny numer sekwencyjny. Ten tryb może być przydatny, jeśli 0 zostało zapisane w kolumnie AUTO_INCREMENT tabeli. (Nawiasem mówiąc, przechowywanie 0 nie jest zalecaną praktyką).

Aby zmienić wartość licznika AUTO_INCREMENT, który ma być używany dla nowych wierszy:

ALTER TABLE mytable AUTO_INCREMENT = value; 

lub SET INSERT_ID = wartość;

O ile nie określono inaczej, wartość zaczyna się od: 1000000 lub określa ją w ten sposób:

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

CZASOMIERZ:

Wartości kolumn TIMESTAMP są konwertowane z bieżącej strefy czasowej na UTC w celu przechowywania iz UTC na bieżącą strefę czasową w celu pobrania.

http://dev.mysql.com/doc/refman/5.1/en/timestamp.html W przypadku jednej kolumny TIMESTAMP w tabeli można przypisać bieżący znacznik czasu jako wartość domyślną i wartość automatycznej aktualizacji.

jedna rzecz, na którą należy uważać podczas używania jednego z tych typów w klauzuli WHERE, najlepiej jest zrobić WHERE datecolumn = FROM_UNIXTIME (1057941242), a nie WHERE UNIX_TIMESTAMP (datecolumn) = 1057941242. zrobienie tego drugiego nie wykorzysta indeksu na tej kolumnie.

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

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

jeśli przekonwertujesz datetime na unix timestamp w MySQL:
A potem dodaj do tego 24 godziny:
A potem przekonwertuj z powrotem na datę i godzinę, magicznie traci godzinę!

Oto, co się dzieje. Podczas konwersji uniksowego znacznika czasu z powrotem na datę i godzinę, strefa czasowa jest brana pod uwagę i tak się składa, że ​​między 28 a 29 października 2006 straciliśmy czas letni i godzinę.

Począwszy od MySQL 4.1.3, funkcje CURRENT_TIMESTAMP (), CURRENT_TIME (), CURRENT_DATE () i FROM_UNIXTIME () zwracają wartości w bieżącej strefie czasowej połączenia , która jest dostępna jako wartość zmiennej systemowej time_zone. Ponadto UNIX_TIMESTAMP () zakłada, że ​​jej argument jest wartością typu data-godzina w bieżącej strefie czasowej.

Bieżące ustawienie strefy czasowej nie wpływa na wartości wyświetlane przez funkcje, takie jak UTC_TIMESTAMP () lub wartości w kolumnach DATA, CZAS lub DATETIME.

UWAGA: TYLKO PRZY AKTUALIZACJI aktualizuje datę i godzinę, jeśli pole zostanie zmienione. Jeśli AKTUALIZACJA nie powoduje zmiany żadnych pól, wówczas data i godzina NIE są aktualizowane!

Dodatkowo, pierwszy TIMESTAMP to zawsze AUTOUPDATE, nawet jeśli nie został określony

Podczas pracy z datami prawie zawsze konwertuję na datę juliańską, ponieważ matematyka danych jest wtedy prostą kwestią dodawania lub odejmowania liczb całkowitych i sekund od północy z tego samego powodu. Rzadko potrzebuję czasu o większej ziarnistości niż sekundy.

Obydwa mogą być przechowywane jako 4-bajtowe liczby całkowite, a jeśli przestrzeń jest naprawdę mała, można je połączyć w czas UNIX (sekundy od epoki 1/1/1970) jako liczbę całkowitą bez znaku, która będzie dobra do około 2106 jako:

's w ciągu 24 godzin = 86400

„Signed Integer max val = 2.147.483.647 - może pomieścić 68 lat sekund

„Unsigned Integer max val = 4 294 967 295 - może pomieścić 136 lat sekund

Protokół binarny:

MySQL 4.1 wprowadził protokół binarny, który umożliwia wysyłanie i zwracanie wartości danych niebędących ciągami znaków w formacie natywnym bez konwersji na format łańcuchowy iz powrotem. (Bardzo użyteczne)

Poza tym mysql_real_query () jest szybsza niż mysql_query (), ponieważ nie wywołuje strlen () do działania na ciągu instrukcji.

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html Protokół binarny obsługuje instrukcje przygotowane po stronie serwera i umożliwia przesyłanie wartości danych w formacie natywnym. Protokół binarny przeszedł sporo zmian we wcześniejszych wydaniach MySQL 4.1.

Możesz użyć makra IS_NUM (), aby sprawdzić, czy pole ma typ liczbowy. Przekaż wartość typu do IS_NUM () i zwraca wartość PRAWDA, jeśli pole jest numeryczne:

Należy zauważyć, że dane binarne MOGĄ być wysyłane w ramach zwykłego zapytania, jeśli uciekniesz przed nim i pamiętaj, że MySQL wymaga tylko tego ukośnika odwrotnego i cudzysłowu. Jest to więc naprawdę łatwy sposób na WSTAWIANIE krótszych ciągów binarnych, takich jak na przykład zaszyfrowane / solone hasła.

Serwer główny:

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_user IDENTIFIED BY „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

Plik dziennika binarnego musi czytać:

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

Możesz usunąć wszystkie binarne pliki dziennika za pomocą instrukcji RESET MASTER lub ich podzbiór za pomocą polecenia PURGE MASTER

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

Normalizacja:

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

Funkcje UDF

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

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

Typy danych:

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/

Należy zwrócić uwagę na to, że na mieszanej tabeli z CHAR i VARCHAR mySQL zmieni CHAR na VARCHAR

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

MySQL zawsze przedstawia daty zaczynając od roku, zgodnie ze standardowymi specyfikacjami SQL i ISO 8601

Różne:

Wyłączenie niektórych funkcji MySQl spowoduje zmniejszenie plików danych i szybszy dostęp. Na przykład:

--datadir określi katalog danych i

--skip-innodb wyłączy opcję inno i zaoszczędzi 10-20 mln

Więcej tutaj http://dev.mysql.com/tech-resources/articles/mysql-c-api.html

Pobierz rozdział 7 - bezpłatny

InnoDB jest platformą transakcyjną, ale wiąże się z nią narzut wydajności. Stwierdziłem, że tabele MyISAM wystarczają na 90% moich projektów. Tabele niezabezpieczone transakcjami (MyISAM) mają kilka własnych zalet, z których wszystkie występują, ponieważ:

nie ma narzutów transakcyjnych:

O wiele szybciej

Mniejsze wymagania dotyczące miejsca na dysku

Do wykonania aktualizacji potrzeba mniej pamięci

Każda tabela MyISAM jest przechowywana na dysku w trzech plikach. Pliki mają nazwy zaczynające się od nazwy tabeli i mają rozszerzenie wskazujące na typ pliku. Plik .frm przechowuje format tabeli. Plik danych ma rozszerzenie .MYD (MYData). Plik indeksu ma rozszerzenie .MYI (MYIndex).

Te pliki można skopiować do lokalizacji przechowywania w stanie nienaruszonym bez korzystania z funkcji kopii zapasowej administratorów MySQL, która jest czasochłonna (podobnie jak przywracanie)

Sztuczka polega na zrobieniu kopii tych plików, a następnie UPUSZCZENIE tabeli. Po przywróceniu plików MySQl rozpozna je i zaktualizuje śledzenie tabeli.

Jeśli musisz wykonać kopię zapasową / przywrócić,

Przywracanie kopii zapasowej lub importowanie z istniejącego pliku zrzutu może zająć dużo czasu w zależności od liczby indeksów i kluczy podstawowych w każdej tabeli. Możesz znacznie przyspieszyć ten proces, modyfikując oryginalny plik zrzutu, otaczając go następującymi elementami:

SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS=0;

.. your dump file ..

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

Aby znacznie zwiększyć szybkość przeładowania, dodaj polecenie SQL SET AUTOCOMMIT = 0; na początku pliku zrzutu i dodaj COMMIT; polecenie do końca.

Domyślnie autocommit jest włączone, co oznacza, że ​​każde polecenie wstawiania w pliku zrzutu będzie traktowane jako oddzielna transakcja i zapisywane na dysku przed rozpoczęciem następnej. Jeśli nie dodasz tych poleceń, ponowne załadowanie dużej bazy danych do InnoDB może zająć wiele godzin ...

Maksymalny rozmiar wiersza w tabeli MySQL to 65 535 bajtów

Efektywna maksymalna długość VARCHAR w MySQL 5.0.3 i dalej = maksymalny rozmiar wiersza (65 535 bajtów)

Wartości VARCHAR nie są wypełniane, gdy są przechowywane. Spacje końcowe są zachowywane, gdy wartości są zapisywane i pobierane, zgodnie ze standardowym SQL.

Wartości CHAR i VARCHAR w MySQL są porównywane bez względu na końcowe spacje.

Użycie znaku CHAR przyspieszy dostęp tylko wtedy, gdy cały rekord ma stały rozmiar. Oznacza to, że jeśli używasz dowolnego obiektu o zmiennej wielkości, równie dobrze możesz sprawić, że wszystkie będą miały zmienny rozmiar. Nie zyskujesz szybkości, używając znaku CHAR w tabeli zawierającej również VARCHAR.

Limit VARCHAR 255 znaków został podniesiony do 65535 znaków od MySQL 5.0.3

Wyszukiwanie pełnotekstowe jest obsługiwane tylko w przypadku tabel MyISAM.

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

Kolumny BLOB nie mają zestawu znaków, a sortowanie i porównanie są oparte na wartościach liczbowych bajtów w wartościach kolumn

Jeśli tryb ścisłego SQL nie jest włączony i do kolumny BLOB lub TEXT zostanie przypisana wartość przekraczająca maksymalną długość kolumny, wartość zostanie obcięta w celu dopasowania i zostanie wygenerowane ostrzeżenie.

Przydatne polecenia:

sprawdź tryb ścisły: SELECT @@ global.sql_mode;

wyłącz tryb ścisły:

SET @@ global.sql_mode = '';

SET @@ global.sql_mode = 'MYSQL40'

lub usuń: sql-mode = "STRICT_TRANS_TABLES, ...

POKAŻ KOLUMNY Z 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/en/information-functions.html#function_last-insert-id last_insert_id ()

pobiera PK z ostatniego wiersza wstawionego w bieżącym wątku. max (pkcolname) pobiera ostatni PK w całości.

Uwaga: jeśli tabela jest pusta, max (pkcolname) zwraca 1 mysql_insert_id () konwertuje zwracany typ natywnej funkcji MySQL C API mysql_insert_id () na typ long (nazwany int w PHP).

Jeśli kolumna AUTO_INCREMENT ma typ kolumny BIGINT, wartość zwrócona przez mysql_insert_id () będzie niepoprawna. Zamiast tego użyj wewnętrznej funkcji MySQL SQL LAST_INSERT_ID () w zapytaniu SQL.

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

Tylko uwaga, że ​​kiedy próbujesz wstawić dane do tabeli i otrzymujesz błąd:

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

używając czegoś takiego jak

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

dzieje się tak dlatego, że nie masz żadnych apostrofów wokół wartości, które próbujesz umieścić w tabeli. Więc powinieneś zmienić swój kod na:

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

przypomnienie, że `` służą do definiowania pól MySQL, baz danych lub tabel, a nie wartości;)

Utracone połączenie z serwerem podczas zapytania:

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

Zapytania dostrajające

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

Cóż, to powinno wystarczyć, by zarobić bonus, myślę, że ... Owoce wielu godzin i wielu projektów ze świetną darmową bazą danych. Rozwijam serwery danych aplikacji na platformach Windows głównie z MySQL. Najgorszy bałagan, jaki musiałem uporządkować, to

Ostateczny koszmar starej bazy danych MySQL

Wymagało to szeregu aplikacji, aby przetworzyć tabele w coś użytecznego przy użyciu wielu wspomnianych tutaj sztuczek.

Jeśli uznasz to za zdumiewająco pomocne, wyrażaj swoje podziękowania, głosując.

Sprawdź także moje inne artykuły i białe księgi na: www.coastrd.com

Mike Trader
źródło
22

Jedną z niezbyt ukrytych cech MySQL jest to, że nie jest zbyt dobry w zgodności z SQL, no cóż, nie ma naprawdę błędów, ale więcej problemów ... :-)

mata
źródło
Powiadomienie innych, że ta lista była cenna podczas przechodzenia z MSSQL do MySQL. Cheers Mat.
GateKiller,
Wiele z tych pułapek pochodzi z wcześniejszych wersji MySQL.
jmucchiello
po pierwsze, nie sądzę, aby kiedykolwiek było możliwe umieszczenie wartości NULL w polu znacznika czasu.
mat
3
MySQL nie jest szczególnie gorszy pod względem zgodności z SQL niż wiele innych baz danych; tak długo, jak trzymasz się rozsądnego podzbioru SQL, możesz ogólnie uniknąć pułapek - co jest więcej niż można powiedzieć na przykład. Niesławne puste ciągi Oracle o wartości NULL.
bobince
1
Możesz wyłączyć niektóre z pułapekSET SESSION sql_mode='ANSI';
Kornel
21

Polecenie, aby dowiedzieć się, jakie tabele są obecnie w pamięci podręcznej:

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

(Z bloga dotyczącego wydajności MySQL )

Eran Galperin
źródło
15

Polecenie, aby dowiedzieć się, kto co robi:

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) 

Możesz zabić proces za pomocą:

mysql>kill 5 
Christian C. Salvadó
źródło
5
POKAŻ PEŁNĄ LISTĘ PROCESÓW, jeśli nie chcesz, aby zapytania były obcinane.
Greg,
11

Szczególnie podoba mi się wbudowana obsługa MySQL dla inet_ntoa()i inet_aton(). To sprawia, że ​​obsługa adresów IP w tabelach jest bardzo prosta (przynajmniej o ile są to tylko adresy IPv4!)

Alnitak
źródło
2
PostgreSQL ma bardzo ładny typ inet, który bardzo ładnie obsługuje ipv4 i ipv6 :-)
mat
Ja też je lubiłem, ale brak konieczności korzystania z nich jest jeszcze lepszy. +1 dla Postgres.
Kornel
11

Uwielbiam on duplicate key(AKA upsert, merge) za wszelkiego rodzaju liczniki tworzone leniwie:

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

Możesz wstawić wiele wierszy w jednym zapytaniu i natychmiast obsłużyć zduplikowany indeks dla każdego z wierszy.

porneL
źródło
10

Ponownie - niezbyt ukryte funkcje, ale naprawdę przydatne:

Funkcja

Łatwo pobierz DDL:

SHOW CREATE TABLE CountryLanguage

wynik:

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

Cecha: funkcja agregująca GROUP_CONCAT () Tworzy połączony ciąg argumentów dla każdego szczegółu i agreguje przez konkatenację tych argumentów na grupę.

Przykład 1: proste

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

Wynik:

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

Przykład 2: wiele argumentów

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

Wynik:

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

Przykład 3: Korzystanie z niestandardowego separatora

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

Wynik:

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

Przykład 4: Kontrolowanie kolejności elementów listy

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

Wynik:

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

Funkcja: COUNT (DISTINCT) z wieloma wyrażeniami

Możesz użyć wielu wyrażeń w wyrażeniu COUNT (DISTINCT ...), aby policzyć liczbę kombinacji.

SELECT COUNT(DISTINCT CountryCode, Language) FROM CountryLanguage

Funkcja / Gotcha: Nie ma potrzeby umieszczania niezagregowanych wyrażeń na liście GROUP BY

Większość systemów RDBMS wymusza zgodność z SQL92 GROUP BY, co wymaga, aby wszystkie niezagregowane wyrażenia z listy SELECT pojawiały się w GROUP BY. W tych systemach RDBMS to stwierdzenie:

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

jest nieprawidłowy, ponieważ lista SELECT zawiera niezagregowaną kolumnę Kraj.Kontynent, która nie pojawia się na liście GROUP BY. W tych systemach RDBMS musisz albo zmodyfikować listę GROUP BY, aby była czytana

GROUP BY   Country.Code, Country.Continent

lub na przykład musisz dodać jakąś bezsensowną agregację do Country.Continent

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

Rzecz w tym, że logicznie rzecz biorąc, nie ma niczego, co domagałby się, aby Kraj. Kontynent został zagregowany. Zobacz, Country.Code jest kluczem podstawowym tabeli Country. Country.Continent jest również kolumną z tabeli Country, a zatem według definicji jest funkcjonalnie zależna od klucza podstawowego Country.Code. Zatem musi istnieć dokładnie jedna wartość w polu Country.Continent dla każdego odrębnego kodu Country.Code. Jeśli zdasz sobie z tego sprawę, to zdasz sobie sprawę, że nie ma sensu agregowanie jej (jest tylko jedna wartość, prawda) ani grupowanie według niej (ponieważ nie sprawi, że wynik będzie bardziej unikalny, ponieważ już grupujesz według pk)

W każdym razie - MySQL umożliwia dołączanie niezagregowanych kolumn do listy SELECT bez konieczności dodawania ich również do klauzuli GROUP BY.

Problem polega na tym, że MySQL nie chroni Cię w przypadku użycia niezagregowanej kolumny. Tak więc zapytanie takie jak to:

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

Zostanie wykonany bez reklamacji, ale kolumna CountryLanguage.Percentage będzie zawierać brak sensu (to znaczy, ze wszystkich procentowych języków jedna z dostępnych wartości procentu zostanie wybrana losowo lub przynajmniej poza Twoją kontrolą.

Zobacz: Obalanie grupy według mitów

anon
źródło
Zezwalanie na kolumny nie zadeklarowane w grupie według jest jedną z moich najmniej ulubionych funkcji pochodzących z Oracle. To wielka trudność, jeśli jesteś przyzwyczajony do Oracle - po prostu pozwala uruchomić zapytanie, wyniki wyglądają dobrze, ale potem zdajesz sobie sprawę, że nie robi tego, co myślałeś.
mbafford,
7

Polecenie „pager” w kliencie

Jeśli masz, powiedzmy, 10000 wierszy w swoim wyniku i chcesz je wyświetlić (przy założeniu, że dostępne są polecenia „less” i „tee”, co zwykle ma miejsce w Linuksie; w Windows YMMV).

pager less
select lots_of_stuff FROM tbl WHERE clause_which_matches_10k_rows;

Znajdziesz je w „mniej” przeglądarce plików, dzięki czemu będziesz mógł ładnie je przeglądać, wyszukiwać itp.

Również

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

Wygodnie zapisze do pliku.

MarkR
źródło
niestety pod oknami, nawet jeśli istnieją „less” i „tee”, sama opcja pagera nie jest obsługiwana. i tak niełatwo
Berry Tsakala
6

Niektóre rzeczy mogą Cię zainteresować:

<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
SorinV
źródło
3

Oto kilka moich wskazówek - pisałem o nich na swoim blogu ( Link )

  1. Nie musisz używać znaku „@” podczas deklarowania zmiennych.
  2. Musisz użyć separatora (domyślnie jest to „;”), aby oddzielić koniec instrukcji - Link
  3. Jeśli próbujesz przenieść dane między MS-SQL 2005 a mySQL, jest kilka opcji do przeskoczenia - Link
  4. Dopasowywanie z uwzględnieniem wielkości liter w mySQL - link
Nikhil
źródło
3

Jeśli zamierzasz pracować z dużymi i / lub wysokimi transakcjami bazami danych InnoDb, naucz się i zrozum Mysql Performance Blog „POKAŻ STATUS INNODB” , stanie się Twoim przyjacielem.

Hawk Kroeger
źródło
3

Jeśli używasz cmdline Mysq, możesz wchodzić w interakcję z wierszem poleceń (na komputerach z systemem Linux - nie jesteś pewien, czy jest to równoważny efekt w systemie Windows), używając krzyku / wykrzyknika. Na przykład:

\! cat file1.sql

wyświetli kod dla plik1.sql. Aby zapisać wyciąg i zapytanie w pliku, użyj funkcji tee

\T filename

aby to wyłączyć użyj \ t

Na koniec, aby uruchomić skrypt, który już zapisałeś, użyj „nazwy pliku źródłowego”. Oczywiście normalną alternatywą jest bezpośrednie wpisanie nazwy skryptu podczas uruchamiania mysql z wiersza poleceń:

    mysql -u root -p < case1.sql

Mam nadzieję, że to komuś się przyda!

Edycja: Właśnie przypomniałem sobie o innym - kiedy wywołując mysql z linii poleceń, możesz użyć przełącznika -t, aby wyjście było w formacie tabeli - prawdziwe dobrodziejstwo z niektórymi zapytaniami (chociaż oczywiście kończenie zapytań za pomocą \ G, jak wspomniano w innym miejscu tutaj jest również pomocny w tym zakresie). O wiele więcej na temat różnych przełączników Narzędzie wiersza poleceń

Właśnie znalazłem zgrabny sposób na zmianę kolejności sortowania (zwykle użyj przypadku ...) Jeśli chcesz zmienić kolejność sortowania (być może sortuj według 1, 4, 3, 2 zamiast 1, 2, 3, 4) możesz skorzystać z funkcji pola w ramach klauzuli Order by. Na przykład

Sortuj według pola (sort_field, 1,4,3,2)

DBMarcos99
źródło
3

Nie sądzę, aby to było specyficzne dla MySQL, ale dla mnie pouczające:

Zamiast pisać

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

Możesz po prostu pisać

WHERE (x.id, x.f2) > (y.id, y.f2)
Johan
źródło
To jest naprawdę fajne, ale jakie byłyby tego przypadki użycia?
mangoDrunk
Może to być przydatne do znajdowania wszystkich rekordów, które są większe niż dany rekord.
Fantius
2

mysqlsla - Jedno z bardzo często używanych narzędzi do analizy logów zapytań. Możesz zobaczyć 10 najgorszych zapytań od czasu ostatniego wprowadzenia wolnych dzienników zapytań. Może również powiedzieć, ile razy zostało uruchomione BAD zapytanie i ile łącznie zajęło to na serwerze.

pawan
źródło
2

Właściwie udokumentowane , ale bardzo irytujące: automatyczne konwersje dla nieprawidłowych dat i innych nieprawidłowych danych wejściowych.

Przed MySQL 5.0.2 MySQL wybacza nielegalne lub niewłaściwe wartości danych i wymusza na nich legalne wartości przy wprowadzaniu danych. W MySQL 5.0.2 i nowszych jest to zachowanie domyślne, ale można zmienić tryb SQL serwera, aby wybrać bardziej tradycyjne traktowanie złych wartości, tak że serwer je odrzuca i przerywa instrukcję, w której występują.

Jeśli chodzi o daty: czasami będziesz miał szczęście, gdy MySQL nie dostosuje danych wejściowych do pobliskich ważnych dat, ale zamiast tego przechowuje je jako, 0000-00-00które z definicji są nieprawidłowe. Jednak nawet wtedy mógłbyś chcieć, aby MySQL zawiódł, zamiast po cichu przechowywać tę wartość za Ciebie.

Arjan
źródło
1

InnoDB domyślnie przechowuje wszystkie tabele w jednym globalnym obszarze tabel, który nigdy się nie zmniejszy .

Możesz użyć, innodb_file_per_tablektóry umieści każdą tabelę w oddzielnym obszarze tabel, który zostanie usunięty po usunięciu tabeli lub bazy danych.

Zaplanuj to z wyprzedzeniem, ponieważ musisz zrzucić i przywrócić bazę danych, aby w przeciwnym razie odzyskać miejsce.

Korzystanie z przestrzeni tabel na tabelę

serbaut
źródło
1

Jeśli wstawisz do kolumny daty i godziny pusty ciąg wartości „”, MySQL zachowa tę wartość jako 00/00/0000 00:00:00. W przeciwieństwie do Oracle, który zapisze wartość zerową.

Devid G
źródło
1

Podczas moich testów porównawczych z dużymi zbiorami danych i polami DATETIME zawsze wolniej wykonać to zapytanie:

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

Niż to podejście:

SELECT * FROM mytable
WHERE date_column BETWEEN '2011-01-01 00:00:00' AND '2011-03-03 23:59:59'
Osvaldo Mercado
źródło