Recursos ocultos do MySQL

101

Trabalho com o Microsoft SQL Server há muitos anos, mas só recentemente comecei a usar o MySQL com meus aplicativos da web e estou faminto por conhecimento.

Para continuar com a longa linha de perguntas sobre "recursos ocultos" , gostaria de saber quaisquer recursos ocultos ou úteis do MySQL que, com sorte, melhorarão meu conhecimento sobre esse banco de dados de código aberto.

GateKiller
fonte

Respostas:

161

Já que você colocou uma recompensa, vou compartilhar meus segredos duramente conquistados ...

Em geral, todos os SQLs que ajustei hoje exigiam o uso de subconsultas. Tendo vindo do mundo do banco de dados Oracle, coisas que eu considerava certas não funcionavam da mesma forma com o MySQL. E minha leitura sobre o ajuste do MySQL me faz concluir que o MySQL está por trás do Oracle em termos de otimização de consultas.

Embora as consultas simples exigidas para a maioria dos aplicativos B2C possam funcionar bem para o MySQL, a maioria dos tipos de consultas de relatórios agregados necessários para o Intelligence Reporting parece exigir um pouco de planejamento e reorganização das consultas SQL para orientar o MySQL a executá-las mais rapidamente.

Administração:

max_connectionsé o número de conexões simultâneas. O valor padrão é 100 conexões (151 desde 5.0) - muito pequeno.

Nota:

conexões consomem memória e seu sistema operacional pode não ser capaz de lidar com muitas conexões.

Os binários do MySQL para Linux / x86 permitem que você tenha até 4096 conexões simultâneas, mas os binários auto-compilados geralmente têm um limite menor.

Defina table_cache para corresponder ao número de suas tabelas abertas e conexões simultâneas. Observe o valor open_tables e se ele estiver crescendo rapidamente, você precisará aumentar seu tamanho.

Nota:

Os 2 parâmetros anteriores podem exigir muitos arquivos abertos. 20 + max_connections + table_cache * 2 é uma boa estimativa para o que você precisa. MySQL no Linux tem uma opção open_file_limit, defina este limite.

Se você tiver consultas complexas, sort_buffer_size e tmp_table_size provavelmente serão muito importantes. Os valores dependem da complexidade da consulta e dos recursos disponíveis, mas 4Mb e 32Mb, respectivamente, são pontos de partida recomendados.

Nota: Estes são valores "por conexão", entre read_buffer_size, read_rnd_buffer_size e alguns outros, o que significa que este valor pode ser necessário para cada conexão. Portanto, considere sua carga e recursos disponíveis ao definir esses parâmetros. Por exemplo, sort_buffer_size é alocado apenas se o MySQL precisar fazer uma classificação. Nota: tenha cuidado para não ficar sem memória.

Se você tiver muitas conexões estabelecidas (ou seja, um site sem conexões persistentes), você pode melhorar o desempenho configurando thread_cache_size para um valor diferente de zero. 16 é um bom valor para começar. Aumente o valor até que seus threads_created não cresçam muito rapidamente.

CHAVE PRIMÁRIA:

Pode haver apenas uma coluna AUTO_INCREMENT por tabela, ela deve ser indexada e não pode ter um valor DEFAULT

KEY é normalmente um sinônimo para INDEX. O atributo de chave PRIMARY KEY também pode ser especificado apenas como KEY quando fornecido em uma definição de coluna. Isso foi implementado para compatibilidade com outros sistemas de banco de dados.

Uma PRIMARY KEY é um índice único onde todas as colunas-chave devem ser definidas como NOT NULL

Se um índice PRIMARY KEY ou UNIQUE consistir em apenas uma coluna que possui um tipo inteiro, você também pode se referir à coluna como "_rowid" nas instruções SELECT.

No MySQL, o nome de uma PRIMARY KEY é PRIMARY

Atualmente, apenas tabelas InnoDB (v5.1?) Suportam chaves estrangeiras.

Normalmente, você cria todos os índices de que precisa ao criar tabelas. Qualquer coluna declarada como PRIMARY KEY, KEY, UNIQUE ou INDEX será indexada.

NULL significa "sem valor". Para testar NULL, você não pode usar os operadores de comparação aritmética, como =, <ou <>. Em vez disso, use os operadores IS NULL e IS NOT NULL:

NO_AUTO_VALUE_ON_ZERO suprime o incremento automático de 0 para que apenas NULL gere o próximo número de sequência. Este modo pode ser útil se 0 foi armazenado na coluna AUTO_INCREMENT de uma tabela. (A propósito, armazenar 0 não é uma prática recomendada.)

Para alterar o valor do contador AUTO_INCREMENT a ser usado para novas linhas:

ALTER TABLE mytable AUTO_INCREMENT = value; 

ou SET INSERT_ID = valor;

A menos que especificado de outra forma, o valor começará com: 1000000 ou especifique-o assim:

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

TIMESTAMPS:

Os valores das colunas TIMESTAMP são convertidos do fuso horário atual em UTC para armazenamento e de UTC no fuso horário atual para recuperação.

http://dev.mysql.com/doc/refman/5.1/en/timestamp.html Para uma coluna TIMESTAMP em uma tabela, você pode atribuir o carimbo de data / hora atual como o valor padrão e o valor de atualização automática.

uma coisa a se observar ao usar um desses tipos em uma cláusula WHERE, é melhor fazer WHERE datecolumn = FROM_UNIXTIME (1057941242) e não WHERE UNIX_TIMESTAMP (datecolumn) = 1057941242. fazer o último não tirará proveito de um índice nessa coluna.

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 você converter uma data e hora em um carimbo de data e hora Unix no MySQL:
E então adicionar 24 horas a ele:
E então convertê-lo de volta em uma data e hora, ele magicamente perde uma hora!

Aqui está o que está acontecendo. Ao converter o timestamp unix de volta para uma data e hora, o fuso horário é levado em consideração e acontece que entre os dias 28 e 29 de outubro de 2006 saímos do horário de verão e perdemos uma hora.

A partir do MySQL 4.1.3, as funções CURRENT_TIMESTAMP (), CURRENT_TIME (), CURRENT_DATE () e FROM_UNIXTIME () retornam valores no fuso horário atual da conexão , que está disponível como o valor da variável de sistema time_zone. Além disso, UNIX_TIMESTAMP () assume que seu argumento é um valor de data e hora no fuso horário atual.

A configuração de fuso horário atual não afeta os valores exibidos por funções como UTC_TIMESTAMP () ou valores nas colunas DATE, TIME ou DATETIME.

NOTA: ON UPDATE atualiza SOMENTE o DateTime se um campo for alterado. Se um UPDATE resultar em nenhum campo sendo alterado, o DateTime NÃO é atualizado!

Além disso, o primeiro TIMESTAMP é sempre AUTOUPDATE por padrão, mesmo se não for especificado

Ao trabalhar com datas, quase sempre convoco para data juliana porque a matemática de dados é então uma simples questão de adicionar ou subtrair inteiros e segundos desde a meia-noite pelo mesmo motivo. É raro eu precisar de uma resolução de tempo de granularidade mais fina do que segundos.

Ambos podem ser armazenados como um número inteiro de 4 bytes e, se o espaço for realmente apertado, podem ser combinados no tempo UNIX (segundos desde a época 01/01/1970) como um número inteiro sem sinal que será bom até cerca de 2106 como:

's em 24 horas = 86400

'Número inteiro assinado val = 2.147.483.647 - pode conter 68 anos de segundos

'Inteiro sem sinal max val = 4.294.967.295 - pode conter 136 anos de segundos

Protocolo Binário:

O MySQL 4.1 introduziu um protocolo binário que permite que valores de dados não string sejam enviados e retornados em formato nativo sem conversão de e para o formato string. (Muito útil)

Além disso, mysql_real_query () é mais rápido que mysql_query () porque não chama strlen () para operar na string de instrução.

http://dev.mysql.com/tech-resources/articles/4.1/prepared-statements.html O protocolo binário suporta instruções preparadas do lado do servidor e permite a transmissão de valores de dados em formato nativo. O protocolo binário passou por muitas revisões durante as versões anteriores do MySQL 4.1.

Você pode usar a macro IS_NUM () para testar se um campo tem um tipo numérico. Passe o valor do tipo para IS_NUM () e ele avalia como TRUE se o campo for numérico:

Uma coisa a notar é que os dados binários PODEM ser enviados dentro de uma consulta regular se você escapar dela e lembrar que o MySQL requer apenas que a barra invertida e o caractere de aspas sejam escapados. Essa é uma maneira realmente fácil de INSERIR strings binárias mais curtas, como senhas criptografadas / com Sal, por exemplo.

Servidor Mestre:

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 . para slave_user IDENTIFICADO POR '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

O arquivo de log binário deve conter:

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

Você pode excluir todos os arquivos de log binários com a instrução RESET MASTER ou um subconjunto deles com PURGE MASTER

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

Normalização:

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

Funções UDF

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

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

Tipos de dados:

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/

Uma coisa a se notar é que em uma tabela mista com CHAR e VARCHAR, mySQL mudará os CHARs para VARCHARs

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

MySQL sempre representa as datas com o ano primeiro, de acordo com as especificações padrão SQL e ISO 8601

Diversos:

Tirar algumas funcionalidades do MySQL resultará em arquivos de dados menores e acesso mais rápido. Por exemplo:

--datadir irá especificar o diretório de dados e

--skip-innodb desligará a opção Inno e economizará 10-20M

Mais aqui http://dev.mysql.com/tech-resources/articles/mysql-c-api.html

Baixe o capítulo 7 - grátis

O InnoDB é transacional, mas há uma sobrecarga de desempenho que vem com ele. Eu descobri que as tabelas MyISAM são suficientes para 90% dos meus projetos. As tabelas não seguras para transações (MyISAM) têm várias vantagens próprias, todas as quais ocorrem porque:

não há sobrecarga de transação:

Muito mais rapido

Requisitos de menor espaço em disco

Menos memória necessária para realizar atualizações

Cada tabela MyISAM é armazenada em disco em três arquivos. Os arquivos têm nomes que começam com o nome da tabela e têm uma extensão para indicar o tipo de arquivo. Um arquivo .frm armazena o formato da tabela. O arquivo de dados tem uma extensão .MYD (MYData). O arquivo de índice possui uma extensão .MYI (MYIndex).

Esses arquivos podem ser copiados para um local de armazenamento intacto, sem o uso do recurso de backup de administradores do MySQL, que é demorado (assim como a restauração)

O truque é fazer uma cópia desses arquivos e então DROP a tabela. Quando você colocar os arquivos de volta, o MySQL irá reconhecê-los e atualizar o rastreamento da tabela.

Se você deve fazer backup / restaurar,

Restaurar um backup ou importar de um arquivo de despejo existente pode levar muito tempo, dependendo do número de índices e chaves primárias que você tem em cada tabela. Você pode acelerar esse processo drasticamente, modificando seu arquivo de despejo original envolvendo-o com o seguinte:

SET AUTOCOMMIT = 0;
SET FOREIGN_KEY_CHECKS=0;

.. your dump file ..

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

Para aumentar muito a velocidade do recarregamento, adicione o comando SQL SET AUTOCOMMIT = 0; no início do arquivo de despejo, e adicione o COMMIT; comando até o fim.

Por padrão, o autocommit está ativado, o que significa que todo e qualquer comando de inserção no arquivo de despejo será tratado como uma transação separada e gravada no disco antes que a próxima seja iniciada. Se você não adicionar esses comandos, recarregar um grande banco de dados no InnoDB pode levar muitas horas ...

O tamanho máximo de uma linha em uma tabela MySQL é 65.535 bytes

O comprimento máximo efetivo de um VARCHAR no MySQL 5.0.3 e em = tamanho máximo da linha (65.535 bytes)

Os valores VARCHAR não são preenchidos quando são armazenados. Os espaços finais são retidos quando os valores são armazenados e recuperados, em conformidade com o SQL padrão.

Os valores CHAR e VARCHAR no MySQL são comparados sem levar em conta os espaços à direita.

O uso de CHAR só irá acelerar seu acesso se todo o registro for de tamanho fixo. Ou seja, se você usar qualquer objeto de tamanho variável, você também pode tornar todos eles de tamanho variável. Você não ganha velocidade usando um CHAR em uma tabela que também contém um VARCHAR.

O limite VARCHAR de 255 caracteres foi aumentado para 65535 caracteres a partir do MySQL 5.0.3

As pesquisas de texto completo são suportadas apenas para tabelas MyISAM.

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

As colunas BLOB não têm conjunto de caracteres e a classificação e comparação são baseadas nos valores numéricos dos bytes nos valores da coluna

Se o modo SQL estrito não estiver ativado e você atribuir um valor a uma coluna BLOB ou TEXT que exceda o comprimento máximo da coluna, o valor será truncado para caber e um aviso será gerado.

Comandos úteis:

verifique o modo estrito: SELECT @@ global.sql_mode;

desligue o modo estrito:

SET @@ global.sql_mode = '';

SET @@ global.sql_mode = 'MYSQL40'

ou remova: sql-mode = "STRICT_TRANS_TABLES, ...

MOSTRAR COLUNAS DE 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 ()

obtém o PK da última linha inserida no thread atual max (pkcolname) obtém o último PK geral.

Nota: se a tabela estiver vazia, max (pkcolname) retorna 1 mysql_insert_id () converte o tipo de retorno da função MySQL C API nativa mysql_insert_id () em um tipo de long (nomeado int em PHP).

Se sua coluna AUTO_INCREMENT tem um tipo de coluna BIGINT, o valor retornado por mysql_insert_id () estará incorreto. Em vez disso, use a função SQL interna do MySQL LAST_INSERT_ID () em uma consulta SQL.

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

Apenas uma observação que quando você tenta inserir dados em uma tabela e obtém o erro:

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

usando algo como

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

é porque você não tem apóstrofos em torno dos valores que está tentando inserir na tabela. Portanto, você deve alterar seu código para:

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

lembrete de que `` são usados ​​para definir campos, bancos de dados ou tabelas MySQL, não valores;)

Conexão perdida com o servidor durante a consulta:

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

Consultas de ajuste

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

Bem, isso deve ser o suficiente para ganhar o bônus, eu acho ... Os frutos de muitas horas e muitos projetos com um ótimo banco de dados gratuito . Eu desenvolvo servidores de dados de aplicativos em plataformas Windows principalmente com MySQL. A pior bagunça que eu tive que resolver foi

O pior pesadelo do banco de dados legado MySQL

Isso exigiu uma série de aplicativos para processar as tabelas em algo útil, usando muitos dos truques mencionados aqui.

Se você achou isso incrivelmente útil, expresse seus agradecimentos votando.

Verifique também meus outros artigos e white papers em: www.coastrd.com

Mike Trader
fonte
22

Um dos recursos não tão ocultos do MySQL é que ele não é muito bom em ser compatível com SQL, bem, não tem bugs, mas, mais pegadinhas ... :-)

esteira
fonte
Deixando outros saberem que esta lista foi valiosa ao mudar do MSSQL para o MySQL. Cheers Mat.
GateKiller de
Muitas dessas pegadinhas são de versões anteriores do MySQL.
jmucchiello
por um lado, acho que nunca será possível colocar um valor NULL em um campo de carimbo de data / hora.
mat
3
O MySQL não é particularmente pior em ser compatível com SQL do que muitos outros bancos de dados; contanto que você se atenha a um subconjunto lógico de SQL, você geralmente pode evitar as pegadinhas - o que é mais do que pode ser dito, por exemplo. As infames strings vazias NULL da Oracle.
bobince,
1
Você pode desativar algumas das pegadinhasSET SESSION sql_mode='ANSI';
Kornel,
21

Um comando para descobrir quais tabelas estão atualmente no cache:

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

(Do blog de desempenho do MySQL )

Eran Galperin
fonte
15

Um comando para descobrir quem está fazendo o quê:

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 você pode matar um processo com:

mysql>kill 5 
CMS
fonte
5
também MOSTRE LISTA DE PROCESSOS COMPLETA se não quiser que as consultas sejam truncadas.
Greg
11

Gosto particularmente do suporte integrado do MySQL para inet_ntoa()e inet_aton(). Ele torna o tratamento de endereços IP em tabelas muito simples (pelo menos desde que sejam apenas endereços IPv4!)

Alnitak
fonte
2
PostgreSQL tem um tipo muito agradável inet, que lida com IPv4 e IPv6 muito nicelly :-)
mat
Eu também gostava deles, mas não precisar usá-los é ainda melhor. 1 para Postgres.
Kornel,
11

Eu amo on duplicate key(também conhecido como upsert, merge) para todos os tipos de contadores criados preguiçosamente:

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

Você pode inserir muitas linhas em uma consulta e lidar imediatamente com o índice duplicado de cada uma das linhas.

porneL
fonte
10

Novamente - não recursos realmente ocultos, mas muito úteis:

Característica

Capture DDL facilmente:

SHOW CREATE TABLE CountryLanguage

resultado:

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

Recurso: Função de agregação GROUP_CONCAT () Cria uma string concatenada de seus argumentos por detalhe, e agrega concatenando-os por grupo.

Exemplo 1: simples

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

Resultado:

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

Exemplo 2: vários argumentos

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

Resultado:

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

Exemplo 3: usando um separador personalizado

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

Resultado:

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

Exemplo 4: controlando a ordem dos elementos da lista

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

Resultado:

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

Característica: COUNT (DISTINCT) com múltiplas expressões

Você pode usar várias expressões em uma expressão COUNT (DISTINCT ...) para contar o número de combinações.

SELECT COUNT(DISTINCT CountryCode, Language) FROM CountryLanguage

Recurso / pegadinha: não há necessidade de incluir expressões não agregadas na lista GROUP BY

A maioria dos RDBMS-es impõe um GROUP BY compatível com SQL92 que requer que todas as expressões não agregadas na lista SELECT apareçam em GROUP BY. Nestes RDBMS-es, esta declaração:

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

não é válido porque a lista SELECT contém a coluna não agregada País.Continente que não aparece na lista GROUP BY. Nestes RDBMS-es, você deve modificar a lista GROUP BY para ler

GROUP BY   Country.Code, Country.Continent

ou você deve adicionar algum agregado sem sentido a Country.Continent, por exemplo

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

Agora, a questão é, logicamente não há nada que exija que o País. Continente deva ser agravado. Veja, Country.Code é a chave primária da tabela Country. Country.Continent também é uma coluna da tabela Country e, portanto, por definições, depende funcionalmente da chave primária Country.Code. Portanto, deve existir exatamente um valor em Country.Continent para cada Country.Code distinto. Se você perceber isso, então perceberá que não faz sentido agregá-lo (há apenas um valor, certo) nem agrupá-lo (pois isso não tornará o resultado mais exclusivo, pois você já está agrupando por em o pk)

De qualquer forma - o MySQL permite incluir colunas não agregadas na lista SELECT sem exigir que você também as adicione à cláusula GROUP BY.

O problema com isso é que o MySQL não o protege no caso de você usar uma coluna não agregada. Então, uma consulta como esta:

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

Será executado sem reclamação, mas a coluna CountryLanguage.Percentage conterá non-sense (ou seja, de todas as percentagens de idiomas, um dos valores disponíveis para a porcentagem será escolhido aleatoriamente ou pelo menos fora do seu controle.

Veja: Desmascarando Grupo por Mitos

anon
fonte
A permissão de colunas não declaradas no grupo por é um dos meus recursos menos favoritos vindo do Oracle. É um grande problema se você está acostumado com o Oracle - ele apenas permite que você execute a consulta, os resultados parecem certos, mas então você percebe que ele não está fazendo o que você pensava.
mbafford
7

O comando "pager" no cliente

Se você tiver, digamos, 10.000 linhas em seu resultado e quiser visualizá-los (isso pressupõe os comandos "less" e "tee" disponíveis, o que normalmente é o caso no Linux; no Windows YMMV.)

pager less
select lots_of_stuff FROM tbl WHERE clause_which_matches_10k_rows;

E você os obterá no visualizador de arquivos "menos" para que possa percorrê-los facilmente, pesquisar etc.

Além disso

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

Escreve convenientemente em um arquivo.

MarkR
fonte
infelizmente no Windows, mesmo se "less" e "tee" existirem, a opção de pager em si não é suportada. não facilmente de qualquer maneira
Berry Tsakala
6

Algumas coisas que você pode achar interessantes:

<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
fonte
3

Aqui estão algumas das minhas dicas - eu escrevi sobre elas no meu blog ( link )

  1. Você não precisa usar o sinal '@' ao declarar variáveis.
  2. Você deve usar um delimitador (o padrão é ';') para demarcar o final de uma instrução - Link
  3. Se você está tentando mover dados entre o MS-SQL 2005 e o mySQL, existem alguns obstáculos para pular - Link
  4. Fazendo correspondências com distinção entre maiúsculas e minúsculas em mySQL - link
Nikhil
fonte
3

Se você vai trabalhar com bancos de dados InnoDb grandes e / ou de alta transação, aprenda e entenda o blog de desempenho do Mysql "MOSTRAR STATUS DO INNODB" , ele se tornará seu amigo.

Hawk Kroeger
fonte
3

Se estiver usando cmdline Mysq, você pode interagir com a linha de comando (em máquinas Linux - não tenho certeza se há um efeito equivalente no Windows) usando o grito / ponto de exclamação. Por exemplo:

\! cat file1.sql

exibirá o código para file1.sql. Para salvar sua declaração e consulta em um arquivo, use a facilidade tee

\T filename

para desligar, use \ t

Por último, para executar um script que você já salvou, use "nome do arquivo fonte". Obviamente, a alternativa normal é direcionar o nome do script ao iniciar o mysql a partir da linha de comando:

    mysql -u root -p < case1.sql

Espero que isso seja útil para alguém!

Edit: Acabei de me lembrar de outro - ao invocar o mysql da linha de comando, você pode usar a opção -t para que a saída esteja no formato de tabela - um benefício real com algumas consultas (embora, é claro, terminar as consultas com \ G como mencionado em outro lugar aqui também é útil a este respeito). Muito mais em vários switches Command Line Tool

Acabei de descobrir uma maneira bacana de alterar a ordem de uma classificação (normalmente use Case ...) Se você quiser alterar a ordem de uma classificação (talvez classifique por 1, 4, 3, 2 em vez de 1, 2, 3, 4) você pode usar a função de campo dentro da cláusula Order by. Por exemplo

Ordem por campo (sort_field, 1,4,3,2)

DBMarcos99
fonte
3

Não acho que isso seja específico do MySQL, mas esclarecedor para mim:

Em vez de escrever

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

Você pode apenas escrever

WHERE (x.id, x.f2) > (y.id, y.f2)
João
fonte
Isso é muito legal, mas quais seriam alguns casos de uso para isso?
mangoDrunk de
Pode ser útil para localizar todos os registros maiores que um determinado registro.
Fantius
2

mysqlsla - Uma das ferramentas de análise de log de consulta lenta muito comumente usada. Você pode ver as 10 piores consultas desde a última vez em que lançou logs de consulta lentos. Ele também pode informar o número de vezes que a consulta BAD foi disparada e quanto tempo total demorou no servidor.

Pawan
fonte
2

Na verdade documentado , mas muito chato: conversões automáticas para datas incorretas e outras entradas incorretas.

Antes do MySQL 5.0.2, o MySQL perdoava os valores de dados ilegais ou impróprios e os coagia a valores legais para entrada de dados. No MySQL 5.0.2 e superior, esse permanece o comportamento padrão, mas você pode alterar o modo SQL do servidor para selecionar um tratamento mais tradicional de valores inválidos, de forma que o servidor os rejeite e aborte a instrução em que eles ocorrem.

Quanto às datas: às vezes você terá "sorte" quando o MySQL não ajustar a entrada para datas válidas próximas, mas em vez disso, armazena-as como as 0000-00-00quais, por definição, são inválidas. No entanto, mesmo assim, você pode querer que o MySQL falhe em vez de armazenar esse valor silenciosamente para você.

Arjan
fonte
1

InnoDB por padrão armazena todas as tabelas em um espaço de tabela global que nunca encolherá .

Você pode usar o innodb_file_per_tablequal colocará cada tabela em um espaço de tabela separado que será excluído quando você eliminar a tabela ou o banco de dados.

Planeje com antecedência para isso, pois você terá que despejar e restaurar o banco de dados para recuperar espaço de outra forma.

Usando espaços de tabela por tabela

Serbaut
fonte
1

Se você inserir na coluna datetime o valor de string vazio "", o MySQL manterá o valor como 00/00/0000 00:00:00. Ao contrário do Oracle, que salvará o valor nulo.

Devid G
fonte
1

Durante meus benchmarks com grandes conjuntos de dados e campos DATETIME, é sempre mais lento para fazer esta consulta:

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

Do que esta abordagem:

SELECT * FROM mytable
WHERE date_column BETWEEN '2011-01-01 00:00:00' AND '2011-03-03 23:59:59'
Osvaldo Mercado
fonte