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 virtualcolumn
FROM 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
SET SESSION sql_mode='ANSI';
Um comando para descobrir quais tabelas estão atualmente no cache:
(Do blog de desempenho do MySQL )
fonte
Um comando para descobrir quem está fazendo o quê:
E você pode matar um processo com:
fonte
Gosto particularmente do suporte integrado do MySQL para
inet_ntoa()
einet_aton()
. Ele torna o tratamento de endereços IP em tabelas muito simples (pelo menos desde que sejam apenas endereços IPv4!)fonte
Eu amo
on duplicate key
(também conhecido como upsert, merge) para todos os tipos de contadores criados preguiçosamente:Você pode inserir muitas linhas em uma consulta e lidar imediatamente com o índice duplicado de cada uma das linhas.
fonte
Novamente - não recursos realmente ocultos, mas muito úteis:
Característica
Capture DDL facilmente:
SHOW CREATE TABLE CountryLanguage
resultado:
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
Resultado:
Exemplo 2: vários argumentos
Resultado:
Exemplo 3: usando um separador personalizado
Resultado:
Exemplo 4: controlando a ordem dos elementos da lista
Resultado:
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:
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
ou você deve adicionar algum agregado sem sentido a Country.Continent, por exemplo
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:
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
fonte
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.)
E você os obterá no visualizador de arquivos "menos" para que possa percorrê-los facilmente, pesquisar etc.
Além disso
Escreve convenientemente em um arquivo.
fonte
Algumas coisas que você pode achar interessantes:
fonte
Não é um recurso oculto, mas útil: http://mtop.sourceforge.net/
fonte
Aqui estão algumas das minhas dicas - eu escrevi sobre elas no meu blog ( link )
fonte
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.
fonte
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:
exibirá o código para file1.sql. Para salvar sua declaração e consulta em um arquivo, use a facilidade tee
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:
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)
fonte
Não acho que isso seja específico do MySQL, mas esclarecedor para mim:
Em vez de escrever
Você pode apenas escrever
fonte
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.
fonte
Na verdade documentado , mas muito chato: conversões automáticas para datas incorretas e outras entradas incorretas.
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-00
quais, 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ê.fonte
O SQL Profiler integrado .
fonte
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_table
qual 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
fonte
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.
fonte
Durante meus benchmarks com grandes conjuntos de dados e campos DATETIME, é sempre mais lento para fazer esta consulta:
Do que esta abordagem:
fonte