Funzionalità nascoste di MySQL


101

Lavoro con Microsoft SQL Server ormai da molti anni, ma solo di recente ho iniziato a utilizzare MySQL con le mie applicazioni web e ho fame di conoscenza.

Per continuare con la lunga serie di domande sulle "funzionalità nascoste" , vorrei conoscere tutte le funzionalità nascoste o utili di MySQL che, si spera, miglioreranno la mia conoscenza di questo database open source.

Risposte:


161

Dal momento che hai offerto una taglia, condividerò i miei segreti conquistati a fatica ...

In generale, tutti gli SQL che ho messo a punto oggi richiedono l'utilizzo di sottoquery. Essendo arrivato dal mondo dei database Oracle, le cose che davo per scontate non funzionavano allo stesso modo con MySQL. E la mia lettura sull'ottimizzazione di MySQL mi fa concludere che MySQL è dietro Oracle in termini di ottimizzazione delle query.

Sebbene le semplici query richieste per la maggior parte delle applicazioni B2C possano funzionare bene per MySQL, la maggior parte del tipo di query di reporting aggregato necessario per Intelligence Reporting sembra richiedere un bel po 'di pianificazione e riorganizzazione delle query SQL per guidare MySQL ad eseguirle più velocemente.

Amministrazione:

max_connectionsè il numero di connessioni simultanee. Il valore predefinito è 100 connessioni (151 dalla 5.0) - molto piccolo.

Nota:

le connessioni richiedono memoria e il tuo sistema operativo potrebbe non essere in grado di gestire molte connessioni.

I binari MySQL per Linux / x86 consentono di avere fino a 4096 connessioni simultanee, ma i binari autocompilati spesso hanno meno limiti.

Imposta table_cache in modo che corrisponda al numero delle tue tabelle aperte e delle connessioni simultanee. Guarda il valore di open_tables e se sta crescendo rapidamente dovrai aumentare le sue dimensioni.

Nota:

I 2 parametri precedenti potrebbero richiedere molti file aperti. 20 + max_connections + table_cache * 2 è una buona stima per ciò di cui hai bisogno. MySQL su Linux ha un'opzione open_file_limit, imposta questo limite.

Se hai query complesse, è probabile che sort_buffer_size e tmp_table_size siano molto importanti. I valori dipenderanno dalla complessità della query e dalle risorse disponibili, ma rispettivamente 4 MB e 32 MB sono punti di partenza consigliati.

Nota: questi sono valori "per connessione", tra read_buffer_size, read_rnd_buffer_size e alcuni altri, il che significa che questo valore potrebbe essere necessario per ogni connessione. Quindi, considera il tuo carico e la risorsa disponibile quando imposti questi parametri. Ad esempio, sort_buffer_size viene allocato solo se MySQL deve eseguire un ordinamento. Nota: fare attenzione a non esaurire la memoria.

Se sono state stabilite molte connessioni (ad esempio un sito web senza connessioni persistenti) potresti migliorare le prestazioni impostando thread_cache_size su un valore diverso da zero. 16 è un buon valore per iniziare. Aumenta il valore finché il tuo thread_created non cresce molto rapidamente.

CHIAVE PRIMARIA:

Può esserci una sola colonna AUTO_INCREMENT per tabella, deve essere indicizzata e non può avere un valore DEFAULT

KEY è normalmente un sinonimo di INDICE. L'attributo chiave PRIMARY KEY può anche essere specificato come KEY quando fornito in una definizione di colonna. Questo è stato implementato per compatibilità con altri sistemi di database.

UNA CHIAVE PRIMARIA è un indice univoco in cui tutte le colonne chiave devono essere definite come NOT NULL

Se un indice PRIMARY KEY o UNIQUE è costituito da una sola colonna che ha un tipo intero, è anche possibile fare riferimento alla colonna come "_rowid" nelle istruzioni SELECT.

In MySQL, il nome di una PRIMARY KEY è PRIMARY

Attualmente, solo le tabelle InnoDB (v5.1?) Supportano le chiavi esterne.

Di solito, crei tutti gli indici di cui hai bisogno quando crei le tabelle. Qualsiasi colonna dichiarata come PRIMARY KEY, KEY, UNIQUE o INDEX verrà indicizzata.

NULL significa "non avere un valore". Per verificare la presenza di NULL, non è possibile utilizzare gli operatori di confronto aritmetico come =, <o <>. Utilizza invece gli operatori IS NULL e IS NOT NULL:

NO_AUTO_VALUE_ON_ZERO sopprime l'incremento automatico per 0 in modo che solo NULL generi il numero di sequenza successivo. Questa modalità può essere utile se 0 è stato memorizzato nella colonna AUTO_INCREMENT di una tabella. (La memorizzazione di 0 non è una pratica consigliata, a proposito.)

Per modificare il valore del contatore AUTO_INCREMENT da utilizzare per le nuove righe:

ALTER TABLE mytable AUTO_INCREMENT = value; 

o SET INSERT_ID = valore;

Se non diversamente specificato, il valore inizierà con: 1000000 o specificarlo così:

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

Timestamp: da

I valori per le colonne TIMESTAMP vengono convertiti dal fuso orario corrente a UTC per l'archiviazione e da UTC al fuso orario corrente per il recupero.

http://dev.mysql.com/doc/refman/5.1/en/timestamp.html Per una colonna TIMESTAMP in una tabella, puoi assegnare il timestamp corrente come valore predefinito e il valore di aggiornamento automatico.

una cosa a cui prestare attenzione quando si utilizza uno di questi tipi in una clausola WHERE, è meglio fare WHERE datecolumn = FROM_UNIXTIME (1057941242) e non WHERE UNIX_TIMESTAMP (datecolumn) = 1057941242. facendo quest'ultimo non si trarrà vantaggio da un indice su quella colonna.

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

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

se converti un datetime in unix timestamp in MySQL:
e poi aggiungi 24 ore ad esso:
e poi lo converti di nuovo in un datetime, perde magicamente un'ora!

Ecco cosa sta succedendo. Quando si converte di nuovo il timestamp unix in un datetime, viene preso in considerazione il fuso orario e accade solo che tra il 28 e il 29 ottobre 2006 siamo usciti dall'ora legale e abbiamo perso un'ora.

A partire da MySQL 4.1.3, le funzioni CURRENT_TIMESTAMP (), CURRENT_TIME (), CURRENT_DATE () e FROM_UNIXTIME () restituiscono valori nel fuso orario corrente della connessione , che è disponibile come valore della variabile di sistema time_zone. Inoltre, UNIX_TIMESTAMP () presuppone che il suo argomento sia un valore datetime nel fuso orario corrente.

L'impostazione del fuso orario corrente non influisce sui valori visualizzati da funzioni come UTC_TIMESTAMP () o sui valori nelle colonne DATE, TIME o DATETIME.

NOTA: SOLO SU AGGIORNAMENTO aggiorna il DateTime se un campo viene modificato Se un UPDATE risulta in nessun campo modificato, il DateTime NON viene aggiornato!

Inoltre, il primo TIMESTAMP è sempre AUTOUPDATE per impostazione predefinita anche se non specificato

Quando lavoro con le date, mi convinco quasi sempre a Julian Date perché la matematica dei dati è quindi una semplice questione di aggiungere o sottrarre numeri interi e secondi da mezzanotte per lo stesso motivo. È raro che abbia bisogno di una risoluzione temporale con una granularità più fine dei secondi.

Entrambi possono essere memorizzati come un numero intero di 4 byte, e se lo spazio è veramente stretto può essere combinato nel tempo UNIX (secondi dall'epoca 1/1/1970) come un numero intero senza segno che sarà valido fino a circa 2106 come:

'secondi in 24 ore = 86400

'Valori interi con segno massimo = 2.147.483.647 - può contenere 68 anni di secondi

"Valori interi non firmati max = 4.294.967.295 - può contenere 136 anni di secondi

Protocollo binario:

MySQL 4.1 ha introdotto un protocollo binario che consente di inviare e restituire valori di dati non di stringa in formato nativo senza conversione da e verso il formato stringa. (Molto utile)

A parte, mysql_real_query () è più veloce di mysql_query () perché non chiama strlen () per operare sulla stringa dell'istruzione.

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html Il protocollo binario supporta istruzioni preparate lato server e consente la trasmissione di valori di dati in formato nativo. Il protocollo binario ha subito un bel po 'di revisione durante le versioni precedenti di MySQL 4.1.

È possibile utilizzare la macro IS_NUM () per verificare se un campo ha un tipo numerico. Passa il valore del tipo a IS_NUM () e restituisce TRUE se il campo è numerico:

Una cosa da notare è che i dati binari POSSONO essere inviati all'interno di una normale query se esegui l'escape e ricordi che MySQL richiede solo la barra rovesciata e il carattere di virgolette. Quindi questo è un modo davvero semplice per INSERIRE stringhe binarie più brevi come password crittografate / salate, ad esempio.

Server principale:

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

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

CONCEDERE REPLICA SLAVE ON . a slave_user IDENTIFICATO DA "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

Il file di registro binario deve leggere:

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

È possibile eliminare tutti i file di registro binari con l'istruzione RESET MASTER o un sottoinsieme di essi con PURGE MASTER

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

Normalizzazione:

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

Funzioni UDF

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

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

Tipi di dati:

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/

Una cosa da notare è che su una tabella mista con CHAR e VARCHAR, mySQL cambierà i CHAR in VARCHAR

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

MySQL rappresenta sempre le date con l'anno prima, in conformità con le specifiche SQL standard e ISO 8601

Varie:

Disattivare alcune funzionalità di MySQl comporterà file di dati più piccoli e un accesso più rapido. Per esempio:

--datadir specificherà la directory dei dati e

--skip-innodb disattiverà l'opzione inno e ti farà risparmiare 10-20 milioni

Maggiori informazioni qui http://dev.mysql.com/tech-resources/articles/mysql-c-api.html

Scarica il capitolo 7 - gratuito

InnoDB è transazionale ma comporta un sovraccarico di prestazioni. Ho trovato le tabelle MyISAM sufficienti per il 90% dei miei progetti. Le tabelle non sicure per le transazioni (MyISAM) hanno diversi vantaggi, che si verificano tutti perché:

non vi è alcun sovraccarico di transazione:

Più veloce

Minori requisiti di spazio su disco

Meno memoria richiesta per eseguire gli aggiornamenti

Ogni tabella MyISAM è archiviata su disco in tre file. I file hanno nomi che iniziano con il nome della tabella e hanno un'estensione per indicare il tipo di file. Un file .frm memorizza il formato della tabella. Il file di dati ha un'estensione .MYD (MYData). Il file indice ha un'estensione .MYI (MYIndex).

Questi file possono essere copiati in una posizione di archiviazione intatta senza utilizzare la funzione di backup degli amministratori di MySQL che richiede tempo (così come il ripristino)

Il trucco è fare una copia di questi file e poi SCARICARE la tabella. Quando rimetti i file, MySQl li riconoscerà e aggiornerà il monitoraggio della tabella.

Se è necessario eseguire il backup / ripristino,

Il ripristino di un backup o l'importazione da un file di dump esistente può richiedere molto tempo a seconda del numero di indici e chiavi primarie presenti su ciascuna tabella. È possibile accelerare notevolmente questo processo modificando il file di dump originale circondandolo con quanto segue:

SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS=0;

.. your dump file ..

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

Per aumentare notevolmente la velocità di ricarica, aggiungere il comando SQL SET AUTOCOMMIT = 0; all'inizio del file dump e aggiungi il COMMIT; comando fino alla fine.

Per impostazione predefinita, autocommit è attivo, il che significa che ogni comando di inserimento nel file di dump verrà trattato come una transazione separata e scritto su disco prima dell'avvio di quello successivo. Se non aggiungi questi comandi, ricaricare un database di grandi dimensioni in InnoDB può richiedere molte ore ...

La dimensione massima di una riga in una tabella MySQL è 65.535 byte

La lunghezza massima effettiva di un VARCHAR in MySQL 5.0.3 e su = dimensione massima della riga (65.535 byte)

I valori VARCHAR non vengono riempiti quando vengono memorizzati. Gli spazi finali vengono conservati quando i valori vengono memorizzati e recuperati, in conformità con lo standard SQL.

I valori CHAR e VARCHAR in MySQL vengono confrontati senza considerare gli spazi finali.

L'utilizzo di CHAR accelera l'accesso solo se l'intero record è di dimensioni fisse. Cioè, se usi qualsiasi oggetto di dimensione variabile, potresti anche renderli tutti di dimensione variabile. Non si guadagna velocità utilizzando un CHAR in una tabella che contiene anche un VARCHAR.

Il limite VARCHAR di 255 caratteri è stato aumentato a 65535 caratteri a partire da MySQL 5.0.3

Le ricerche full-text sono supportate solo per le tabelle MyISAM.

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

Le colonne BLOB non hanno un set di caratteri e l'ordinamento e il confronto si basano sui valori numerici dei byte nei valori delle colonne

Se la modalità SQL rigorosa non è abilitata e si assegna un valore a una colonna BLOB o TEXT che supera la lunghezza massima della colonna, il valore viene troncato per adattarsi e viene generato un avviso.

Comandi utili:

controlla la modalità rigorosa: SELECT @@ global.sql_mode;

disattiva la modalità rigorosa:

SET @@ global.sql_mode = '';

SET @@ global.sql_mode = 'MYSQL40'

o rimuovi: sql-mode = "STRICT_TRANS_TABLES, ...

MOSTRA COLONNE DA mytable

SELEZIONA 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 ()

ti dà il PK dell'ultima riga inserita nel thread corrente max (pkcolname) ti fa l'ultimo PK in totale.

Nota: se la tabella è vuota, max (pkcolname) restituisce 1 mysql_insert_id () converte il tipo restituito della funzione API C MySQL nativa mysql_insert_id () in un tipo di long (denominato int in PHP).

Se la tua colonna AUTO_INCREMENT ha un tipo di colonna BIGINT, il valore restituito da mysql_insert_id () non sarà corretto. Utilizzare invece la funzione SQL MySQL interna LAST_INSERT_ID () in una query SQL.

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

Solo una nota che quando stai cercando di inserire dati in una tabella e ottieni l'errore:

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

usando qualcosa di simile

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

è perché non hai apostrofi sui valori che stai cercando di inserire nella tabella. Quindi dovresti cambiare il tuo codice in:

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

ricorda che `` vengono utilizzati per definire campi, database o tabelle MySQL, non valori;)

Connessione al server persa durante la query:

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

Query di ottimizzazione

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

Beh, questo dovrebbe bastare per guadagnare il bonus penserei ... I frutti di tante ore e tanti progetti con un ottimo database gratuito . Sviluppo server dati applicativi su piattaforme Windows principalmente con MySQL. Il peggior pasticcio che ho dovuto sistemare è stato

L'incubo definitivo del database legacy MySQL

Ciò ha richiesto una serie di applicazioni per elaborare le tabelle in qualcosa di utile utilizzando molti dei trucchi menzionati qui.

Se lo hai trovato incredibilmente utile, esprimi i tuoi ringraziamenti votandolo.

Controlla anche i miei altri articoli e white paper su: www.coastrd.com


22

Una delle caratteristiche non così nascoste di MySQL è che non è molto bravo a essere conforme a SQL, beh, non i bug in realtà, ma, più trucchi ... :-)


Altre lettere sanno che questo elenco è stato prezioso quando si è passati da MSSQL a MySQL. Saluti Mat.
GateKiller

Molti di questi trucchi provengono da versioni precedenti di MySQL.
jmucchiello

per uno, non penso che sarà mai possibile mettere un valore NULL in un campo timestamp.
mat

3
MySQL non è particolarmente peggio per essere conforme a SQL rispetto a molti altri database; fintanto che ti attieni a un sottoinsieme sano di SQL, puoi generalmente evitare i trucchi, il che è più di quanto si possa dire per es. Le famigerate stringhe NULL vuote di Oracle.
bobince

1
Puoi disabilitare alcuni trucchiSET SESSION sql_mode='ANSI';
Kornel

21

Un comando per scoprire quali tabelle sono attualmente nella cache:

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

(Dal blog sulle prestazioni di MySQL )


15

Un comando per scoprire chi sta facendo cosa:

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) 

E puoi terminare un processo con:

mysql>kill 5 

5
anche SHOW FULL PROCESSLIST se non si desidera che le query vengano troncate.
Greg

11

Mi piace particolarmente il supporto integrato di MySQL per inet_ntoa()e inet_aton(). Rende la gestione degli indirizzi IP nelle tabelle molto semplice (almeno fintanto che sono solo indirizzi IPv4!)


2
PostgreSQL ha un tipo inet molto carino, che gestisce ipv4 e ipv6 molto bene :-)
mat

Anche a me piacevano, ma non doverli usare affatto è ancora meglio. +1 per Postgres.
Kornel

11

Adoro on duplicate key(AKA upsert, merge) per tutti i tipi di contatori creati pigramente:

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

È possibile inserire molte righe in una query e gestire immediatamente l'indice duplicato per ciascuna riga.


10

Ancora una volta - funzionalità non proprio nascoste, ma davvero utili:

caratteristica

Afferra facilmente DDL:

SHOW CREATE TABLE CountryLanguage

produzione:

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

Funzionalità: funzione aggregata GROUP_CONCAT () Crea una stringa concatenata dei suoi argomenti per dettaglio e aggrega concatenando quelli per gruppo.

Esempio 1: semplice

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

Produzione:

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

Esempio 2: più argomenti

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

Produzione:

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

Esempio 3: utilizzo di un separatore personalizzato

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

Produzione:

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

Esempio 4: controllo dell'ordine degli elementi dell'elenco

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

Produzione:

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

Funzionalità: COUNT (DISTINCT) con più espressioni

È possibile utilizzare più espressioni in un'espressione COUNT (DISTINCT ...) per contare il numero di combinazioni.

SELECT COUNT(DISTINCT CountryCode, Language) FROM CountryLanguage

Funzionalità / Gotcha: non è necessario includere espressioni non aggregate nell'elenco GROUP BY

La maggior parte dei RDBMS applica un GROUP BY conforme a SQL92 che richiede che tutte le espressioni non aggregate nell'elenco SELECT appaiano in GROUP BY. In questi RDBMS, questa dichiarazione:

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

non è valido, perché l'elenco SELECT contiene la colonna Country.Continent non aggregata che non compare nell'elenco GROUP BY. In questi RDBMS, è necessario modificare l'elenco GROUP BY da leggere

GROUP BY   Country.Code, Country.Continent

oppure è necessario aggiungere un aggregato di non senso a Country.Continent, ad esempio

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

Ora, il fatto è che logicamente non c'è nulla che esiga che Country.Continent debba essere aggravato. Vedi, Country.Code è la chiave primaria della tabella Country. Country.Continent è anche una colonna della tabella Country ed è quindi, per definizioni, funzionalmente dipendente dalla chiave primaria Country.Code. Quindi, deve esistere esattamente un valore in Country.Continent per ogni distinto Country.Code. Se te ne accorgi, allora ti rendi conto che non ha senso aggregarlo (c'è solo un valore, giusto) né raggrupparlo (poiché non renderà il risultato più unico dato che stai già raggruppando per il pk)

Comunque - MySQL ti consente di includere colonne non aggregate nell'elenco SELECT senza richiedere di aggiungerle anche alla clausola GROUP BY.

Il trucco con questo è che MySQL non ti protegge nel caso in cui ti capiti di utilizzare una colonna non aggregata. Quindi, una query come questa:

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

Verrà eseguito senza reclamo, ma la colonna CountryLanguage.Percentage conterrà non ha senso (vale a dire, di tutte le percentuali delle lingue, uno dei valori disponibili per la percentuale verrà scelto a caso o almeno fuori dal tuo controllo.

Vedi: Debunking Group By Myths


Il permesso di colonne non dichiarate nel gruppo da è una delle mie caratteristiche meno preferite provenienti da Oracle. È un grosso problema se sei abituato a Oracle: ti consente solo di eseguire la query, i risultati sembrano corretti, ma poi ti rendi conto che non sta facendo quello che pensavi che fosse.
mbafford

7

Il comando "cercapersone" nel client

Se hai, diciamo, 10.000 righe nel risultato e desideri visualizzarle (questo presuppone i comandi "less" e "tee" disponibili, che normalmente è il caso in Linux; in Windows YMMV.)

pager less
select lots_of_stuff FROM tbl WHERE clause_which_matches_10k_rows;

E li otterrai nel visualizzatore di file "meno" in modo da poterli sfogliare bene, cercare, ecc.

Anche

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

Scriverà comodamente su un file.


sfortunatamente sotto Windows, anche se esistono "less" e "tee", l'opzione pager stessa non è supportata. non facilmente comunque
Berry Tsakala

6

Alcune cose che potresti trovare interessanti:

<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

Ecco alcuni dei miei suggerimenti: ne ho parlato nel mio blog ( Link )

  1. Non è necessario utilizzare il segno "@" quando si dichiarano le variabili.
  2. Devi usare un delimitatore (il valore predefinito è ';') per delimitare la fine di un'istruzione - Link
  3. Se stai cercando di spostare i dati tra MS-SQL 2005 e mySQL, ci sono alcuni ostacoli da superare: Link
  4. Esecuzione di corrispondenze con distinzione tra maiuscole e minuscole in mySQL - link

3

Se hai intenzione di lavorare con database InnoDb di grandi dimensioni e / o con transazioni elevate, impara e comprendi "MOSTRA LO STATO INNODB" Mysql Performance Blog , diventerà tuo amico.


3

Se si utilizza cmdline Mysq, è possibile interagire con la riga di comando (su macchine Linux - non sono sicuro che ci sia un effetto equivalente su Windows) utilizzando il punto esclamativo / stridente. Per esempio:

\! cat file1.sql

visualizzerà il codice per file1.sql. Per salvare l'estratto conto e la query in un file, utilizzare la funzione tee

\T filename

per disattivarlo, usa \ t

Infine, per eseguire uno script che hai già salvato, usa "nome file sorgente". Ovviamente, l'alternativa normale è inserire il nome dello script quando si avvia mysql dalla riga di comando:

    mysql -u root -p < case1.sql

Spero che sia utile a qualcuno!

Modifica: ne ho appena ricordato un altro: quando si richiama mysql dalla riga di comando è possibile utilizzare l'opzione -t in modo che l'output sia in formato tabella - un vero vantaggio con alcune query (anche se ovviamente terminare le query con \ G come menzionato altrove qui è anche utile in questo senso). Molto di più su varie opzioni Command Line Tool

Ho appena scoperto un modo accurato per cambiare l'ordine di un ordinamento (normalmente usa Case ...) Se vuoi cambiare l'ordine di un ordinamento (forse ordinare per 1, 4, 3, 2 invece di 1, 2, 3, 4) è possibile utilizzare la funzione campo all'interno della clausola Order by. Per esempio

Ordina per campo (sort_field, 1,4,3,2)


3

Non penso che questo sia specifico per MySQL, ma per me illuminante:

Invece di scrivere

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

Puoi solo scrivere

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

È davvero interessante, ma quali sarebbero alcuni casi d'uso per questo?
mangoDrunk

Potrebbe essere utile per trovare tutti i record più grandi di un dato record.
Fantius

2

mysqlsla - Uno degli strumenti di analisi del log delle query lente molto comunemente usati. Puoi vedere le prime 10 query peggiori dall'ultima volta che hai implementato log delle query lente. Può anche dirti il ​​numero di volte che la query BAD è stata lanciata e quanto tempo totale ha impiegato sul server.


2

Veramente documentato , ma molto fastidioso: conversioni automatiche per date errate e altri input errati.

Prima di MySQL 5.0.2, MySQL perdona valori di dati illegali o impropri e li costringe a valori legali per l'immissione dei dati. In MySQL 5.0.2 e versioni successive, questo rimane il comportamento predefinito, ma è possibile modificare la modalità SQL del server per selezionare un trattamento più tradizionale dei valori errati in modo tale che il server li rifiuti e annulli l'istruzione in cui si verificano.

Per quanto riguarda le date: a volte sarai "fortunato" quando MySQL non adatta l'input a date valide vicine, ma invece lo memorizza come 0000-00-00che per definizione non è valido. Tuttavia, anche in questo caso potresti aver voluto che MySQL fallisse invece di memorizzare silenziosamente questo valore per te.



1

InnoDB per impostazione predefinita memorizza tutte le tabelle in un tablespace globale che non si ridurrà mai .

È possibile utilizzare innodb_file_per_tableche inserirà ciascuna tabella in uno spazio tabella separato che verrà eliminato quando si rilascia la tabella o il database.

Pianificare in anticipo per questo poiché è necessario eseguire il dump e ripristinare il database per recuperare spazio in caso contrario.

Utilizzo di spazi tabelle per tabella


1

Se inserisci nella colonna datetime il valore stringa vuoto "", MySQL manterrà il valore 00/00/0000 00:00:00. A differenza di Oracle, che salverà il valore nullo.


1

Durante i miei benchmark con set di dati di grandi dimensioni e campi DATETIME, è sempre più lento eseguire questa query:

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

Di questo approccio:

SELECT * FROM mytable
WHERE date_column BETWEEN '2011-01-01 00:00:00' AND '2011-03-03 23:59:59'
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.