Escolar Documentos
Profissional Documentos
Cultura Documentos
de Dados
SUMRIO
Captulo 1 Viso Geral da Otimizao .......................................................03
1.1 - Limitaes do Projeto MySQL/Trocas ...........................................03
1.2 - Portabilidade .................................................................................04
1.3 - Para que Utilizamos o MySQL? ....................................................05
1.4 - O Pacote de Benchmark do MySQL .............................................07
1.5 - Utilizando seus Prprios Benchmarks ..........................................08
Captulo 2 Otimizando SELECTs e Outras Consultas ..............................10
2.1 - Sintaxe de EXPLAIN (Obter informaes sobre uma SELECT) ...10
2.2 - Estimando o Desempenho de uma Consulta ................................19
2.3 - Velocidade das Consultas que Utilizam SELECT .........................20
2.4 - Como o MySQL Otimiza Clusulas WHERE ................................20
2.5 - Como o MySQL Otimiza IS NULL .................................................22
2.6 - Como o MySQL Otimiza Clusulas DISTINCT .............................23
2.7 - Como o MySQL Otimiza LEFT JOIN e RIGHT JOIN ....................24
2.8 - Como o MySQL Otimiza Clusulas ORDER BY ...........................25
2.9 - Como o MySQL Otimiza Clusulas LIMIT ....................................27
2.10 - Performance das Consultas que Utilizam INSERT .....................27
2.11 - Performance das Consultas que Utilizam UPDATE ...................30
2.12 - Performance das Consultas que Utilizam DELETE ....................30
2.13 - Mais Dicas sobre Otimizaes ....................................................30
Captulo 3 Detalhes Sobre Locks ...............................................................34
3.1 - Como o MySQL Trava as Tabelas ................................................34
3.2 - Detalhes sobre Lock de Tabelas ...................................................35
Captulo 4 Otimizando a Estrutura de Banco de Dados ...........................37
4.1 - Opes do Projeto ........................................................................37
4.2 - Deixando os Dados com o Menor Tamanho Possvel ..................37
4.3 - Como o MySQL Utiliza ndices .....................................................39
4.4 - ndices de Colunas ........................................................................41
4.5 - ndices de Mltiplas Colunas ........................................................42
4.6 - Como o MySQL Conta as Tabelas Abertas ..................................43
4.7 - Como o MySQL Abre e Fecha as Tabelas ...................................43
4.8 - Desvantagem em Criar um Nmero Grande de Tabelas no Mesmo
Banco de Dados ...............................................................................................45
Captulo 5 Otimizando o Servidor MySql ...................................................46
5.1 - Sintonia dos Parmetros em Tempo de Sistema/Compilao e na
Inicializao ......................................................................................................46
5.2 - Parmetros de Sintonia do Servidor .............................................47
5.3 - Como a Compilao e a Ligao Afetam a Velocidade do MySql 49
5.4 - Como o MySQL Utiliza a Memria ................................................51
5.5 - Como o MySQL Utiliza o DNS ......................................................53
5.6 - Sintaxe de SET .............................................................................53
Captulo 6 Detalhes de Disco ......................................................................59
6.1 - Utilizando Links Simblicos ...........................................................61
6.1.1 - Utilizando Links Simblicos para Bancos de Dados ........61
6.1.2 - Utilizando Links Simblicos para Tabelas ........................62
6.1.3 - Usando Links Simblicos para Bancos de Dados no
Windows ...........................................................................................................63
.
O mostrado acima quer dizer que no se deve usar o MySQL para verificar o
contedo dos campos, mas deve se fazer isto no aplicativo.
1.2. Portabilidade
Como todos os servidores SQL implementam diferentes partes de SQL,
trabalhoso escrever aplicativos SQL portveis. Para selects/inserts muito simples
muito fcil, mas quanto mais recursos voc precisa, mais difcil se torna. Se voc quiser
uma aplicao quue rpida com muitos bancos de dados ela se torna ainda mais difcil.
Para fazer um aplicativo portvel complexo voc precisa escolher um nmero de
servidores SQL com o qual ele deve trabalhar.
Voc pode utilizar o MySQL programa/web-page crash-me
http://www.mysql.com/information/crash-me.php - para encontrar funes, tipos e
limites que voc pode utilizar com uma seleo de servidores de bancos de dados. O
Crash-me agora testa quase tudo possvel, mas continua compreensvel com
aproximadamente 450 itens testados.
Por exemplo, voc no deve ter nomes de colunas maior do que 18 caracteres se
desejar utilizar o Informix ou DB2.
Os programas de benchmarks e crash-me do MySQL so bastante
independentes do bancos de dados. Dando uma olhada em como ns os tratamos, voc
pode sentir o que necessrio para escrever sua aplicao independente do banco de
dados. Os benchmarks podem ser encontrados no diretrio sql-bench na distribuio
fonte do MySQL. Eles so escritos em Perl com a interface de banco de dados DBI (que
resolve a parte do problema de acesso).
Veja http://www.mysql.com/information/benchmarks.html para os resultados
deste benchmark.
Como pode ser visto nestes resultados, todos os bancos de dados tem alguns
pontos fracos. Isto , eles possuem diferentes compromissos de projeto que levam a
comportamentos diferentes.
Se voc procura por independencia de banco de dados, precisar ter uma boa
idia dos gargalos de cada servidor SQL. O MySQL muito rpido para recuperao e
atualizao de dados, mas ter problemas em misturar leituras/escritas lentas na mesma
tabela. O Oracle, por outro lado, possui um grande problema quando voc tentar acessar
registros que foram recentemente atualizados (at eles serem atualizados no disco).
Bancos de dados transacionais geralmente no so muito bons gerando tabelas de
resumo das tabelas log, nestes casos o travamento de registros praticamente intil.
Para fazer sua aplicao realmente independente de banco de dados, voc
precisar definir uma interface que possa ser expandida, por meio da qual voc far a
manipulao dos dados. Como o C++ est disponvel na maioria dos sistemas, faz
sentido utilizar classes C++ para fazer a interface ao banco de dados.
Se voc utilizar algum recurso especfico para algum banco de dados (como o
comando REPLACE no MySQL), voc deve codificar um mtodo para os outros
serviodores SQL para implementar o mesmo recurso (mas mais lento). Com o MySQL
voc pode utilizar a sintaxe /*! */ para adicionar palavras chave especficas do MySQL
para uma query. O cdigo dentro de /**/ ser tratado como um comentrio (ignorado)
pela maioria dos servidores SQL.
Se alta performance REAL mais importante que exatido, como em algumas
aplicaes WEB, uma possibilidade criar uma camada de aplicao que armazena
todos os resultados para lhe fornecer uma performance ainda mais alta. Deixando
resultados antigos 'expirar' depois de um tempo, voc pode manter o cache
razoavelmente atual. Isto muito bom no caso de uma carga extremamente pesada, pois
neste caso voc pode aumentar o cache dinamicamente e configurar o tempo de
expirao maior at que as coisas voltem ao normal.
Neste caso a informao de criao de tabelas devem conter informaes do
tamanho inicial do cache e com qual frequncia a tabela, normalmente, deve ser
renovada.
Segundos Segundos
367
249
464
1206
121126
1634
20800
877
17614
Segundos Segundos
381
206
619
3460
2692
4012
11291
1801
4802
10
O exemplo acima demonstra que o MySQL pode excutar 1.000.000 expresses + ou em 0.32 segundos em um PentiumII 400MHz.
Todas funes MySQL devem ser bem otimizadas, mas existem algumas excesses e o
benchmark(loop_count,expression) uma tima ferramenta para saber se existe um
problema com sua query.
EXPLAIN nome_tabela
EXPLAIN SELECT opes_select
11
id
Identificador SELECT, o nmero sequncial desta SELECT dentro da
consulta.
select_type
Tipo de clusula SELECT, que pode ser uma das seguintes:
SIMPLE
SELECT simples (sem UNIONs ou subqueries).
PRIMARY
SELECT mais externa.
12
UNION
Segunda SELECT e as SELECTs posteriores do UNION
DEPENDENT UNION
Segunda SELECT e SELECTs posteriores do UNION, dependente da
subquery exterior.
SUBQUERY
Primeiro SELECT na subquery.
DEPENDENT SUBQUERY
Primeiro SELECT, dependente da subquery exterior.
DERIVED
SELECT de tabela derivada (subquery na clusula FROM).
table
A tabela para a qual a linha de sada se refere.
type
system
A tabela s tem uma linha (= tabela de sistema). Este um caso especial
do tipo de join const.
const
13
eq_ref
Uma linha ser lida desta tabela para cada combinao de linhas da tabela
anterior. Este o melhor tipo de join depois dos tipos const. usado quando todas as
partes do ndice so usados pela join e o ndice nico (UNIQUE) ou uma chave
primria (PRIMARY KEY).
eq_ref pode ser usado para coluna indexadas que comparada com o\ operador
=. O item comparado pode ser uma constante ou uma expresso que usa colunas de
tabelas que so lidas antes desta tabela.
Nos seguintes examplos, ref_table poder usar eq_ref
ref
Todas as colunas com valores de ndices correspondentes sero lidos desta tabela
para cada combinao de registros da tabela anterior. ref usado se o join usa apenas o
prefixo mais a esquerda da chave, ou se a chave no nica (UNIQUE) ou uma chave
primria (PRIMARY KEY) (em outras palavras, se a join no puder selecionar um
nico registro baseado no valor da chave). Se a chave que usada coincide apenas em
alguns registros, este tipo de join bom.
ref pode ser usado para colunas indexadas que so comparadas com o operador =.
Nos seguintes exemplos, ref_table poder usar ref
ref_or_null
Como ref, mas com o adicional que faremos uma busca extra para linhas com NULL.
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
Esta otimizao do tipo join nova para o MySQL 4.1.1 e mais usada na
resoluo de sub queries.
range
14
Apenas registros que esto numa dada faixa sero retornados, usando um ndice
para selecionar os registros. A coluna key indica qual ndice usado. key_len contm a
maior parte da chave que foi usada. A coluna ref ser NULL para este tipo.
range pode ser usado para quando uma coluna de chave comparada a uma
constante com =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN e IN.
SELECT * FROM range_table WHERE key_column = 10;
SELECT * FROM range_table WHERE key_column BETWEEN 10 and 20;
SELECT * FROM range_table WHERE key_column IN (10, 20, 30);
SELECT * FROM range_table WHERE key_part1= 10 and key_part2 IN (10,
20, 30);
index
Isto o mesmo que ALL, exceto que apenas a rvore de ndice varrida. Isto
normalmente mais rpido que ALL, j que o arquivo de ndice normalmente menor
que o arquivo de dados.
Ele pode ser usado quando a consulta s usa colunas que so parte de um ndice.
ALL
Ser feita uma varredura completa da tabela para cada combinao de registros da
tabela anterior. Isto normalmente no bom se a tabela a primeiro tabela no marcada
como const, e normalmente muito ruim em todos os casos ordenados. Voc
normalmente pode ebitar ALL adicionando mais ndices, assim o registro pode ser
retornado baseado em valores constantes ou valores de colunas de tabelas anteriores.
possible_keys
A coluna possible_keys indica quais ndices o MySQL pode utilizar para encontrar
os registros nesta tabela. Note que esta coluna totalmente independente da ordem das
tabelas. Isto significa que algumas das chaves em possible_keys podem no ser usadas
na prtica com a ordem de tabela gerada.
Se esta coluna for NULL, no existem ndices relevantes. Neste caso, voc poder
melhora a performance de sua query examinando a clusula WHERE para ver se ela
refere a alguma coluna ou colunas que podem ser indexadas. Se for verdade, crie um
ndice apropriado e confira a consulta com EXPLAIN novamente.
Para ver os ndices existentes em uma tabela, utilize SHOW INDEX FROM
nome_tabela.
key
15
A coluna key indica a chave (ndice) que o MySQL decidiu usar. A chave ser
NULL se nenhum ndice for escolhido. Para forar o MySQL a usar um ndice listado
na coluna possible_keys, use USE INDEX/IGNORE INDEX em sua consulta.
Executando myisamchk -- ou ANALYSE TABLE na tabela tambm ajudar o
otimizador a escolher ndices melhores.
key_len
A coluna key_len indica o tamanho da chave que o MySQL decidiu utilizar. O
tamanho ser NULL se key for NULL. Note que isto nos diz quantas partes de
uma chave multi-partes o MySQL realmente est utilizando.
ref
A coluna ref exibe quais colunas ou contantes so usadas com a key para
selecionar registros da tabela.
rows
A coluna rows informa o nmero de linhas que o MySQL deve examinar para
executar a consulta.
Extra
Distinct
Not exists
Assume que t2.id definido com NOT NULL. Neste caso o MySQL ir
percorrer t1 e procurar pelos registros em t2 atravs de t1.id. Se o MySQL encontrar
um registro combinando em t2, ele sabe que t2.id nunca poder ser NULL e no ir
percorrer at o resto dos registros em t2 que possuirem o mesmo id. Em outras
16
palavras, para cada registro em t1 o MySQL s precisa fazer uma nica pesquisa em
t2, independente de quantos registros coincidentes existirem em t2.
Using filesort
O MySQL precisar fazer uma passada extra para descobrir como recuperar
os registros na ordem de classificao. A classificao feita indo atravs de todos
os registros de acordo com join type e armazenar a chave de ordenao mais o
ponteiro para o registro para todos os registros que combinarem com o WHERE.
Ento as chaves so classificadas. Finalmente os registros so recuperados na ordem
de classificao.
Using index
Using temporary
Using where
Uma clusula WHERE ser utilizada para restringir quais registros sero
combinados com a prxima tabela ou enviar para o cliente. se voc no possui esta
informao e a tabela do tipo ALL ou index, pode existir alguma coisa errada na
sua query (Se voc no pretender examinar todos os registros da tabela).
Se voc desejar deixar suas consultas o mais rpido possvel, voc deve dar uma
olhada em Using filesort e Using temporary.
Voc pode ter uma boa indicao de quo boa sua join multiplicando todos os
valores na coluna rows na sada de EXPLAIN. Isto deve dizer a grosso modo quantos
registros o MySQL deve examinar para executar a consulta. Este nmero tambm
usado quando voc restringe consultas com a varivel max_join_size.
O exemplo a seguir mostra como um JOIN pode ser otimizado progressivamente
utilizando a informao fornecida por EXPLAIN.
17
Suponha que voc tem a instruo SELECT exibida abaixo, que voc est
examinando utilizando EXPLAIN:
EXPLAIN SELECT tt.TicketNumber, tt.TimeIn,
tt.ProjectReference, tt.EstimatedShipDate,
tt.ActualShipDate, tt.ClientID,
tt.ServiceCodes, tt.RepetitiveID,
tt.CurrentProcess, tt.CurrentDPPerson,
tt.RecordVolume, tt.DPPrinted, et.COUNTRY,
et_1.COUNTRY, do.CUSTNAME
FROM tt, et, et AS et_1, do
WHERE tt.SubmitTime IS NULL
AND tt.ActualPC = et.EMPLOYID
AND tt.AssignedPC = et_1.EMPLOYID
AND tt.ClientID = do.CUSTNMBR;
Tipo da coluna
CHAR(10)
CHAR(10)
CHAR(10)
CHAR(15)
CHAR(15)
Coluna
ActualPC
AssignedPC
ClientID
EMPLOYID
CUSTNMBR
ndice
ActualPC
AssignedPC
ClientID
EMPLOYID (chave primria)
CUSTNMBR (chave primria)
Initially, before any optimizations have been performed, the EXPLAIN statement
produces the following information:
table
et
do
et_1
tt
type possible_keys
key key_len
ALL PRIMARY
NULL NULL
ALL PRIMARY
NULL NULL
ALL PRIMARY
NULL NULL
ALL AssignedPC,ClientID,ActualPC NULL NULL
range checked for each record (key map: 35)
ref
NULL
NULL
NULL
NULL
rows
74
2135
74
3872
Extra
18
Como o tipo ALL em todas tabelas, esta sada indica que o MySQL est
gerando um produto Cartesiano de todas as tabelas! Isto levar muito tempo para ser
executado, pois o produto do nmero de registros em cada tabela deve ser examinado !
Neste caso, existem 74 * 2135 * 74 * 3872 registros. Se as tabelas forem maiores,
imagine quanto tempo este tipo de consulta pode demorar.
Um dos problemas aqui que o MySQL no pode (ainda) utilizar ndices em
colunas de maneira eficiente se elas foram declaras ide forma diferente. Neste contexto,
VARCHAR e CHAR so o mesmo a menos que tenham sido declarados com tamanhos
diferentes. Como tt.ActualPC declarado como CHAR(10) e et.EMPLOYID
declarado como CHAR(15), existe aqui uma diferena de tamanho.
Para corrigir esta diferena entre tamanhos de registros, utilize ALTER TABLE
para alterar o tamanho de ActualPC de 10 para 15 caracteres:
mysql> ALTER TABLE tt MODIFY ActualPC VARCHAR(15);
rows
3872
Extra
Using
2135
74
1
Isto no est perfeito, mas est bem melhor ( o produto dos valores de rows
agora menor por um fator de 74 ). Esta verso executada em vrios segundos.
Uma segunda alterao pode ser feita para eliminar as diferenas de tamanho das
colunas para as comparaes tt.AssignedPC = et_1.EMPLOYID e tt.ClientID =
do.CUSTNMBR
mysql> ALTER TABLE tt MODIFY AssignedPC VARCHAR(15),
->
MODIFY ClientID
VARCHAR(15);
et_1
do
possible_keys
PRIMARY
AssignedPC,
ClientID,
ActualPC
eq_ref PRIMARY
eq_ref PRIMARY
key
key_len ref
NULL
NULL
NULL
ActualPC 15
et.EMPLOYID
PRIMARY
PRIMARY
15
15
rows Extra
74
52
Using
tt.AssignedPC 1
tt.ClientID
1
19
O problema restante que, por padro, o MySQL assume que valores na coluna
tt.ActualPC esto distribudos igualmente, e este no o caso para a tabela tt.
Felizmente, fcil informar ao MySQL sobre isto:
shell> myisamchk --analyze PATH_TO_MYSQL_DATABASE/tt
shell> mysqladmin refresh
et
et_1
do
possible_keys key
AssignedPC
NULL
ClientID,
ActualPC
eq_ref PRIMARY
eq_ref PRIMARY
eq_ref PRIMARY
key_len ref
NULL
NULL
PRIMARY 15
PRIMARY 15
PRIMARY 15
rows Extra
3872 Using
tt.ActualPC
1
tt.AssignedPC 1
tt.ClientID
1
Perceba que a coluna rows na sada de EXPLAIN uma boa ajuda para
otimizador de joins do MySQL. Para otimizar uma consulta, voc deve conferir se os
nmeros esto perto da realidade. Se no, voc pode obter melhor desempenho
utilizando STRAIGHT_JOIN em sua instruo SELECT e tentar listar as tabelas em
uma ordem diferente na clusula FROM.
20
crescer. Quando os dados se tornam muito grandes para o cache, as coisas comearo a
ficar bem mais lentas at que suas aplicaes estejam limitadas a buscas em disco (o
que aumenta em N log N). Para evitar isto, aumente o cache de ndice quando os dados
crescerem.
Para ajudar o MySQL a otimizar melhor as consultas, execute myisamchk -analyze em uma tabela depois dela ter sido carregada com dados relevantes. Isto
atualiza um valor para cada parte do ndice que indica o nmero mdio de
registros que tem o mesmo valor. (Para ndices nicos, isto sempre 1, claro).
O MySQL usar isto para decidir qual ndice escolher quando voc conectar
duas tabelas utilizando uma 'expresso no constante'. Os resultados de analyze
podem ser conferidos utilizando SHOW INDEX FROM nome_tabela e
examindo a coluna Cardinality.
Para ordenar um ndice e dados de acordo com um ndice, utilize myisamchk -sort-index --sort-records=1 (se voc deseja ordenar pelo ndice 1). Se voc
possui um ndice unico no qual deseja ler todos registros na ordem do ndice,
esta uma boa forma para torn-lo mais rpido. Perceba entretanto, que esta
ordenao no foi escrita de maneira otimizada e levar muito tempo em tabelas
grandes!
21
Enlaos de constantes:
22
Antes de dar sada em cada registro, aqueles que no combinam com a clusula
HAVING so ignorados.
23
ref_or_null funciona fazendo primeiro uma leitura na chave indicada e depois disto
uma busca separada por linhas com chave NULL.
Note que a otimizao s pode tratar um nvel IS NULL.
SELECT * FROM t1,t2 where (t1.a=t2.a AND t2.a IS NULL) OR (t1.b=t2.b
AND t2.b IS NULL);
No caso acima o MySQL s usar busca de chave na parte (t1.a=t2.a AND t2.a
IS NULL) e no poder usar a parte da chave em b.
24
25
Isto pode ser feito mais rpido j que o MySQL pode agora usar a tabela t2 antes
da tabela t1 se resultasse consulta melhor. Para forar uma ordem de tabela especfica,
use STRAIGHT JOIN.
O MySQL ir fazer uma pesquisa completa em b j que o LEFT JOIN ir
fora-lo a ser lido antes de d.
A correo neste caso alterar a consulta para:
SELECT * FROM b,a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d
(d.key=a.key)
WHERE b.key=d.key
*
*
*
*
*
FROM
FROM
FROM
FROM
FROM
t1
t1
t1
t1
t1
ORDER
WHERE
WHERE
ORDER
WHERE
BY key_part1,key_part2,...
key_part1=constante ORDER BY key_part2
key_part1=constante GROUP BY key_part2
BY key_part1 DESC,key_part2 DESC
key_part1=1 ORDER BY key_part1 DESC,key_part2
Alguns casos onde o MySQL no pode usar ndices para resolver o ORDER BY:
(Note que o MySQL ainda usar ndices para encontrar o registro que coincide com a
clusula WHERE):
26
Voc est unindo muitas tabelas e as colunas nas quais voc est fazendo um
ORDER BY no so todas da primeira tabela que no const e que usada
para retornar registros. (Esta a primeira tabela na sada do EXPLAIN que no
usa um mtodo de busca de registro const).
Voc tem diferentes expresses ORDER BY e GROUP BY.
O ndice da tabela usada um tipo de ndice que no armazena registros em
ordem. (Como o ndice HASH em tabelsn HEAP).
Nestes casos onde o MySQL tem que ordenar o resultado, ele usa o seguinte algoritmo:
Voc pode verificar com EXPLAIN SELECT ... ORDER BY se o MySQL pode
usar ndices para resolver a consulta. Se voc obtiver Using filesort na coluna extra,
ento o MySQL no pode usar ndices para resolver o ORDER BY.
Se voc quiser ter uma velocidade ORDER BY maior, primeiro voc deve ver se
voc pode fazer que o MySQL use ndices em vez de fazer um fase de ordenao extra.
Se no for possvel, ento voc pode fazer:
27
Por padro, o MySQL ordena todas as consultas GROUP BY x,y[,...] como se voc
tivesse especificado ORDER BY x,y[,...]. Se voc incluir a clusula ORDER BY
explicitamente, o MySQL a otimizar sem qualquer penalidade na velocidade, embora a
ordenacao ainda ocorra. Se a consulta inclui um GROUP BY mas voc deseja evitar a
sobrecarga da ordenar o resultado, voc pode suprimir a ordenacao especificando
ORDER BY NULL:
INSERT INTO foo SELECT a,COUNT(*) FROM bar GROUP BY a ORDER BY NULL;
Conexo: (3)
Enviar a consulta para o servidor: (2)
Analisar a consulta (2)
Inserir o registro: (1 x tamanho do registro)
Inserir os ndices: (1 x nmero de ndices)
Fechar: (1)
28
Note que LOAD DATA INFILE tamb faz a otimizao acima se voc a
insero for em uma tabela vazia; a principal diferena com o procedimento acima qeu
voc pode deixar o myisamchk alocar muita mais memria temporria para a criao
do ndice que voc deseje que o MySQL alocasse para todas as recriaes de ndice.
Desde o MySQL 4.0 voc tambm pode usar ALTER TABLE nome_tbl
em
vez
de
DISABLE
KEYS
myisamchk
--keys-used=0
-rq
/caminho/para/bd/nome_tbl e ALTER TABLE nome_tbl ENABLE KEYS em vez
29
mysql>
mysql>
mysql>
mysql>
Voc pode acelerar inseres feitas usando vrias instrues bloqueando suas
tabelas:
LOCK TABLES a WRITE;
INSERT INTO a VALUES (1,23),(2,34),(4,33);
INSERT INTO a VALUES (8,26),(6,29);
UNLOCK TABLES;
30
31
32
33
34
35
36
Um cliente emite uma SELECT que exige muito tempo para ser executada.
Outro cliente ento executa um UPDATE na tabela usada. Este cliente ter que
esperar at que a SELECT seja terminada.
Outro cliente executa outra instruo SELECT na mesma tabela. Como
UPDATE tem maior prioridade que SELECT, esta SELECT ir esperar pelo
trmino da UPDATE. Ela tambm ir esperar pelo trmino da primeira
SELECT!
Uma thread est esperando por algo do tipo disco cheio, caso em que todas as
threads que desejam acessar a tabela com problema iro ser colocadas em estado
de espera at que mais espao em disco seja disponvel.
Tente deixar suas instrues SELECT sempre rpidas. Voc pode ter que criar
algumas tabelas de resumo para fazer isto.
Inicie o mysqld com --low-priority-updates. Isto ir fornecer a todas instrues
que atualizam (modificam) uma tabela prioridade menor que uma instruo
SELECT. Neste caso a ltima instruo SELECT no cenrio anterior deveria
executar antes da instruo INSERT.
Voc pode fornecer a uma instruo INSERT, UPDATE ou DELETE
especfica menor prioridade com o atributo LOW_PRIORITY.
37
A varredura da tabela muito mais lenta porque voc tem que ler os ndices para
encontrar os dados.
No podem ser usados apenas a tabela de ndices para recuperar dados para uma
consulta.
Voc perde muito espao de armazenagem, j que que os ndices devem ser
duplicados nos ns (pois os registros no podem ser armazenados nos ns).
Delees iro degenerar a tabela depois de um tempo (j que os ndices nos ns
normalmente no so atualizados na deleo).
mais difcil fazer o cache somente dos dados de ndices.
38
Utilize os tipos mais eficientes (menores) sempre que possvel. O MySQL tem
vrios tipos especializados que economizam espao em disco e memria.
Utilize tipos inteiros menores se possvel para obter tabelas menores. Por
exemplo, MEDIUMINT normalmente melhor que INT.
Declare colunas para serem NOT NULL se possvel. Isto deixa tudo mais
rpido e voc economiza um bit por coluna. Perceba que se voc realmente
precisa de NULL nas suas aplicaes, podem ser usados. Tente simplesmente
no us-la em todas as colunas por padro.
Se voc no possui nenhuma coluna de tamanho varivel (VARCHAR, TEXT
ou BLOB), um formato de registro de tamanho fixo para utilizado. Isto mais
rpido mas infelizmente pode ocupar mais espao.
O ndice primrio de uma tabela deve ser o mais curto possvel. Isto torna a
identificao de um registro fcil e eficiente.
Para cada tabela, voc deve decidir qual metdo de armazenamento/ndice
utilizar.
Crie somente os ndices necessrios. ndices so bons para recuperao mas
ruins quando voc precisa armazenar os dados rapidamente. Se na maioria das
vezes voc acessa uma tabela pesquisando em uma combinao de colunas, crie
um ndice para elas. A primeira parte do ndice deve ser a coluna mais utilizada.
Se voc SEMPRE utiliza vrias colunas, deve usar a coluna com mais
duplicaes em primeiro lugar para obter melhor compactao do ndice.
Se for melhor que uma coluna tenha um prefixo nico nos primeiros caracteres,
melhor indexar somente este prefixo. O MySQL suporta um ndice em uma
parte de uma coluna de caracteres. ndices menores so mais rpidos no
somente porque eles exigem menos espao em disco mas tambm porque eles
iro fornecer a voc mais acerto no cache de ndice e isto diminui acessos a
disco.
Em algumas circunstncias pode ser benfico dividir uma tabela que varrida
frequentemente em duas. Isto verdade especificamente se a tabela tiver um
formato dinmico e for possvel utilizar um formato de tabela esttico que possa
ser usada para encontrar os registros relevantes quando se fizer uma varredura da
tabela.
39
40
decidindo qual ndice ir encontrar menos registros e usar este ndice para recuperar os
registros.
Se a tabela possuir um ndice de mltiplas colunas, qualquer prefixo mais
esquerda do ndice pode ser usado pelo otimizador para encontrar registros. Por
exemplo, se voc possui um ndice de trs colunas em (col1, col2, col3), voc tem
capacidades de busca indexada em (col1), (col1, col2) e (col1, col2, col3).
O MySQL no pode utilizar um ndice parcial se as colunas no formarem um
prefixo mais esquerda do ndice. Suponha que voc tenha as instrues SELECT
mostradas abaixo:
mysql> SELECT * FROM nome_tabela WHERE col1=val1;
mysql> SELECT * FROM nome_tabela WHERE col2=val2;
mysql> SELECT * FROM nome_tabela WHERE col2=val2 AND col3=val3;
41
42
inteira. A sintaxe para utilizar na instruo CREATE TABLE para indexar um prefixo
de uma coluna se parece com o exemplo a seguir:
INDEX nome_indice (nome_campo(tamanho))
Para colunas BLOB e TEXT, voc deve indexar um prefixo da coluna. O ndice
pode ter at 255 bytes.
No MySQL Verso 3.23.23 ou posterior, voc pode tambm criar ndices
FULLTEXT especiais. Eles so utilizados para pesquisas textuais. Somente o tipo de
tabela MyISAM suporta ndices FULLTEXT e apenas para colunas CHAR,
VARCHAR e TEXT. Indexao sempre acontece sobre toda a coluna e indexao
parcial (prefixo) no suportada.
43
O valor Open tables de 12 ode ser bastante estranho se voc s possui 6 tabelas.
O MySQL multithreaded, portanto ele pode haver clientes enviando consultas
para uma determinada tabela simultaneamente. Para minimizar o problema com dois
clientes tendo diferentes estados no mesmo arquivo, a tabela aberta
independentemente por cada thread concorrente. Isto exige mais memria mas
normalmente aumentar o desempenho. Com tabelas ISAM e MyISAM, um descritor
extra de arquivo necessrio para o arquivo de dados, para cada cliente que tem a tabela
aberta. O descritor de arquivo de ndice compartilhado entre todas as threads.
44
Quando a cache est cheia e um thread tenta abrir uma tabela que no est na
cache.
Quando a cache contm mais que table_cache entradas e uma thread no est
mais usando uma tabela.
Quando algum executa mysqladmin refresh ou mysqladmin flush-tables.
Quando algum executa uma instruo FLUSH TABLES.
Tabelas que no estiverem em uso so liberadas, na ordem LRU (least-recentlyused), ou seja, a tabela que foi usada menos rcentemente.
Se o cache estiver cheio e nenhuma tabelas pode ser liberada, mas uma nova
tabela precisar ser aberta, o cache extendido temporariamente quando
necessrio.
Se o cache estiver no estado temporariamente extendido e uma tabela vai do
estado em-uso para o fora-de-uso, a tabela fechada e liberada do cache.
A table is opened for each concurrent access. This means the table needs to be
opened twice if two threads access the same table or if a thread accesses the table twice
in the same query (for example, by joining the table to itself).
Uma tabela aberta para cada acesso simultneo. Isto significa a tabela precisa ser
aberta duas vezes se duas threads acessam a mesma tabela ou se uma thread acessa a
tabela duas vezes na mesma consulta (por exemplo, fazendo um join da tabela com ela
mesma). A primeira abertura de qualquer tabela exige dois descritores de arquivos; cada
uso adicional da tabela exige somente um descritor. O descritor extra para a primeira
abertura para o arquivo de ndice: este descritor compartilhado entre todas as
threads.
45
Se voc est abrindo uma tabela com a instruo HANDLER nome_tabela OPEN,
uma tabela dedicada alocada para a thread. Este objeto da tabela no compartilhado
por outras threads e no ser fechado at que a thread chame HANDLER nome_tabela
CLOSE ou seja finalizada. Quando isto acontece, a tabela colocada de volta na cache
de tabela (se a cache no estiver cheia).
Voc pode conferir se o seu cache de tabela est muito pequeno conferindo a
varivel opened_tables do mysqld. Se este valor for muito grande, mesmo se voc no
fez vrios FLUSH TABLES, voc deve aumentar o tamanho da sua cache de tabelas.
46
47
current value: 5
current value: 1048540
current value: 32768
current value: 5
current value: 300
current value: 100
current value: 1000
current value: 0
current value: 28800
current value: 131072
current value: 1048540
current value: 0
current value: 10
current value: 1048576
current value: 4294967295
current value: 100
current value: 10
current value: 20
current value: 16777216
current value: 4294967295
current value: 1024
current value: 32
current value: 4294967295
current value: 8388608
current value: 16384
current value: 10
current value: 30
current value: 60
current value: 131072
current value: 262144
current value: 2
current value: 2097116
current value: 64
current value: 10
current value: 1048576
current value: 131072
wait_timeout
48
Se existir um servidor mysqld em execuo, voc pode ver quais valores ele est
usando atualmente para as variveis executando esta instruo:
mysql> SHOW VARIABLES;
Se voc possui pelo menos 256M de memria e vrias tabelas e deseja obter o
melhor desempenho com um nmero moderado de clientes, deve utilizar algo como:
shell> mysqld_safe --key_buffer_size=64M --table_cache=256 \
--sort_buffer_size=4M --read_buffer_size=1M &
49
Se possui apenas 128M de memria e apenas algumas poucas tabelas, mas ainda
deseja realizar vrias ordenaes, voc pode utilizar:
shell> mysqld_safe --key_buffer_size=16M --sort_buffer_size=1M
Se voc possuir pouca memria e tiver muitas conexes, utilize algo como:
shell> mysqld_safe --key_buffer_size=512K --sort_buffer_size=100K \
--read_buffer_size=100K &
ou mesmo isto:
shell> mysqld_safe --key_buffer_size=512K --sort_buffer_size=16K \
--table_cache=32 --read_buffer_size=8K -O net_buffer_length=1K
&
Tenha certeza que a opo --help seja a ltima do comando; de outra forma o
efeito de qualquer opes listadas depois na linha de comando no sero refletidas na
sada.
50
Se voc utiliza o pgcc e compila tudo com -O6, o servidor mysqld 1% mais
rpido do que com o gcc 2.95.2.
Se voc liga dinamicamente (sem -static), o resultado 13% mais lento no
Linux. Note que voc ainda pode utilizar uma biblioteca do MySQL
dinamicamente ligada sua aplicao cliente. s o servidor que crtico para
performance.
Se voc corta seu binrio mysqld com strip libexec/mysqld, o binrio gerado
pode ficar at 4% mais rpido.
Para uma conexo de um cliente para um servidor em execuo na mesma
mquina, se voc conecta utilizando TCP/IP em vez de utilizar um arquivo
socket Unix, o rendimento 7.5% mais lento no mesmo computador. (Se voc
fizer conexo localhost, o MySQL ir, por padro, utilizar sockets).
Para conexes TCP/IP de um cliente para um servidor, conectando a um
servidor remoto em outra mquina ser 8-11% mais lento que conectando ao
servidor local na mesma mquina, mesmo para conexes Ethernet de 100M.
Quando executar o nosso teste de benchamrk usando conexes seguras (todos os
dados crptografados com suporte interno SSL) ele se torna 55% mais lento.
Se voc compilar com --with-debug=full, a maioria das consultas ser 20% mais
lentas. Algumas consultas podem demorar muito mais tempo (por exemplo, os
benchmarks do MySQL demonstram 35% de perda). Se utilizar --with-debug, a
queda ser de apenas 15%. Para uma verso do mysqld compilada com --withdebug=full, voc pode desabilitar a verificao de memria em tempo de
execuo iniciando-o com a opo --skip-safemalloc. O resultado final neste
caso deve estar prximo de quando compilado com --with-debug.
Em um Sun UltraSPARC-IIe, Forte 5.0 4% mais rpido que gcc 3.2.
51
52
53
SET configura vrias opes que afetam a operao do servidor ou seu cliente.
Os seguintes exemplos mostram as diferentes sintaxes que se pode usar para
configurar variveis:
Em verses antigas do MySQL permitiamos o uso da sintaxe SET OPTION,
mas esta sintaxe agora est obsoleta.
No MySQL 4.0.3 adicionamos as opes GLOBAL e SESSION e acessamos as
variveis de inicializao mais importantes.
LOCAL pode ser usado como sinniumo de SESSION.
54
Isto idntico a:
SET @@session.max_join_size=@@global.max_join_size;
Se voc quiser restringir o valor mximo com o qual uma varivel de servidor
pode ser configurado com o comando SET, voc pode especifica-lo usando a opo de
linha de comando --maximum-variable-name.
Voc pode obter uma lista da maioria das variveis com SHOW VARIABLES.
Voc pode obter o valor de uma varivel especfica com a sintaxe
@@[global.|local.]variable_name:
SHOW VARIABLES like "max_join_size";
SHOW GLOBAL VARIABLES like "max_join_size";
SELECT @@max_join_size, @@global.max_join_size;
Segue aqui a descrio das variveis que usam uma sintaxe SET no padro e
algumas das outras variveis. A definio das outras variveis podem ser encontrados
na seo variveis de sistema, entre as opes de inicializao ou na descrio de
SHOW VARIABLES.
55
AUTOCOMMIT= 0 | 1
Se configurado com 1 todas alteraes em uma tabela ser feita de uma vez.
Para iniciar uma transao de vrios comandos, deve ser usada a instruo
BEGIN. Se configurado com 0 deve ser usado COMMIT/ROLLBACK para
aceitar/recusar aquela transao. Note que quando voc altera do modo noAUTOCOMMIT para AUTOCOMMIT, o MySQL ir fazer um COMMIT
automtico em quaisquer transaes abertas.
BIG_TABLES = 0 | 1
Se definido com 1, todas as tabelas temporrias so armazenadas no disco em
vez de o ser na meria. Isto ser um pouco mais lento, mas voc no ter o erro
The table tbl_name is full para grandes operaes SELECT que exigem uma
tabela temporria maior. O valor padro para uma nova conexo 0 (isto , usa
tabelas
temporrias
em
memria)
Esta
opo
era
chamada
SQL_BIG_TABLES. No MySQL 4.0 voc normalmente nunca deve precisar
deste parmetro j que o MySQL converter automaticamente tabelas em
memria para tabelas em disco se isto for necessrio.
DATE_FORMAT = format_str
Determina como o servidor converte valores DATE para strings. Esta varivel
est disponvel como uma opo global, local ou de linha de comando.
format_str pode ser especificado convenientemente usando a funo
GET_FORMAT().
DATETIME_FORMAT = format_str
Determina como o servidor converte valores DATETIME para string. Esta
varivel est disponvel como uma opo global, local ou de linha de comando.
format_str pode ser especificada convenientemente usando a funo
GET_FORMAT().
INSERT_ID = #
Configura o valor que ser usado pelo comando INSERT ou ALTER TABLE
seguinte ao inserir um valor AUTO_INCREMENT. Isto usado
principalmente com o log de atualizaes.
56
LAST_INSERT_ID = #
Configura o valor a ser retornado de LAST_INSERT_ID(). Ele armazenado
no log de atualizaes quando voc utiliza LAST_INSERT_ID() em um
comando que atualiza uma tabela.
LOW_PRIORITY_UPDATES = 0 | 1
Se configurado com 1, todas instrues INSERT, UPDATE, DELETE e
LOCK TABLE WRITE iro esperar at que no existam SELECT ou LOCK
TABLE READ pendentes na tabela afetada. Esta opo era chamada
SQL_LOW_PRIORITY_UPDATES.
Que equivalente a:
mysql> UPDATE mysql.user SET Password=PASSWORD('newpass')
WHERE User='bob' AND Host='%.loc.gov';
->
57
QUERY_CACHE_TYPE
=
OFF
QUERY_CACHE_TYPE = 0 | 1 | 2
ON
DEMAND,
Define a configurao da cache de consultas para esta thread. Set query cache
setting for this thread.
Opo
0 ou OFF
1 ou ON
2 ou
DEMAND
Descrio
No armazena ou recupera resultados.
Armazena todos os resultados, exceto consultas SELECT
SQL_NO_CACHE ....
Armazena apenas consultas SELECT SQL_CACHE ....
SQL_AUTO_IS_NULL = 0 | 1
Se configurado com 1 (padro) o ltimo registro inserido em uma tabela com um
regitro auto_incremnto pode ser encontrado com a seguinte construo:
WHERE auto_increment_column IS NULL. Isto usado por alguns
programas ODBC como o Access.
SQL_BIG_SELECTS = 0 | 1
Se configurado com 0, o MySQL aborta as instrues SELECTs que
provavelmente levam muito tempo (isto , instrues para as quais o otimizador
estima que o nmero de registros examinados provavelmente ir exceder o valor
de MAX_JOIN_SIZE. Isto til quando uma instruo WHERE no
aconselhada for utilizado. O valor padro para uma nova conexo 1 (que
permitir qualquer instruo SELECT).
Se voc definir MAX_JOIN_SIZE com um valor diferente de DEFAULT,
SQL_BIG_SELECTS ser definida com 0.
SQL_BUFFER_RESULT = 0 | 1
SQL_BUFFER_RESULT fora para que o resultado das SELECT's seja
colocado em tabelas temporrias. Isto ir ajudar o MySQL a liberar mais cedos
bloqueios de tabela e ajudaro em casos onde elas ocupam muito tempo para
enviar o conjunto de resultados para o cliente.
SQL_SAFE_UPDATES = 0 | 1
Se configurado com 1, o MySQL ir aborar se tentarmos fazer um UPDATE ou
DELETE sem utilizar uma chave ou LIMIT na clusula WHERE. Desta forma
possvel capturar atualizaes erradas ao criarmos comandos SQL
manualmente.
58
SQL_LOG_OFF = 0 | 1
Se configurado com 1, nenhum registro ser feito no log padro para este
cliente, se o cliente tiver o privilgio SUPER.
SQL_LOG_BIN = 0 | 1
Se configurada com 0, nenhum registro feito no log binrio para o cliente, se o
cliente tiver o privilgio SUPER.
SQL_LOG_UPDATE = 0 | 1
Se configurado com 0, nenhum registro ser feito no log de atualizaes para o
cliente, se o cliente tiver o privilgio SUPPER. Esta varivel est obsoleta a
partir da verso 5.0.
SQL_QUOTE_SHOW_CREATE = 0 | 1
Se configurado com 1, SHOW CREATE TABLE ir colocar os nomes de
tabela e colunas entre aspas. Est ligado por padro, para que replicao de
tabelas com nomes de colunas estranhos funcione.
TIME_FORMAT = format_str
Determina como o servidor converte valores TIME para string. Esta varivel
est disponvel como uma opo global, local ou de linha de comando.
format_str pode ser especificada convenientemente usando a funo
GET_FORMAT()
59
6. Detalhes de Disco
6.1. Utilizando Links Simblicos
Striping
Striping significa que voc possui vrios discos e coloca o
primeiro bloco no primeiro disco, o segundo bloco no segundo disco, e o
N-simo no (N mdulo nmero_de_discos) disco, e assim por diante. Isto
significa que se o seu tamanho de dados normais menos que o tamanho
do bloco (ou perfeitamente alinhado) voc ir obter um desempenho
muito melhor. Striping muito dependente do SO e do tamanho do
bloco. Portanto mea a performance de sua aplicao com diferentes
tamanhos de blocos.
Perceba que a diferena de velocidade para striping muito
dependente dos parmetros. Dependendo de como voc configura os
parmetros do striping e do nmero de discos voc pode obter uma
diferena de vrias ordens de grandeza. Note que voc deve escolher a
otimizao randmica ou pelo acesso sequencial.
60
No Linux, voc pode obter um desempenho muito melhor (cerca de 100% sobre
carga pode ser comum) utilizando hdparm para configurar sua interface de
disco! O exemplo a seguir deve ser muito til para o MySQL (e provavelmente
vrias outras aplicaes):
hdparm -m 16 -d 1
61
Voc pode mover tabelas e bancos de dados do diretrio de banco de dados para
outras localizaes e troc-los por links simblicas para os novos locais. Voc pode
fazer isto, por exemplo, para mover um banco de dados para um sistema de arquivos
com mais espao livre ou aumentar a velocidade de seu sistema espalhando suas tabelas
para discos diferentes.
A maneira recomendada de se fazer isto ligar simbolicamente bancos de dados
a discos diferentes e s ligar tabelas como ltimo recurso.
Agora, para qualquer tabela tbl_a em db1, tambm aparecer uma tabela tbl_a
em db2. Se uma thread atualizar db1.tbl_a e outra atualizar db2.tbl_a, ocorrero
porblemas.
Se voc realmente precisar disto, voc deve alterar o cdigo seguinte em
mysys/mf_format.c:
if (flag & 32 || (!lstat(to,&stat_buff) &&
S_ISLNK(stat_buff.st_mode)))
para
if (1)
62
63
shell>
shell>
shell>
shell>
cd
ln
ln
ln
/path/to/datadir/db1
-s tbl1.frm tbl2.frm
-s tbl1.MYD tbl2.MYD
-s tbl1.MYI tbl2.MYI
Agora se uma thread l db1.tbl1 e outra thread atualiza db1.tbl2, haver problemas:
a cache de consultas ser enganada (ela acreditar que tbl1 no foi atualizado e
retornar resultados desatualizados), o comando ALTER em tbl2 tambm ir falhar.
64
dados, voc deve mov-lo para D:\data antes do link simblico ser efetivado. (Para
evitar problemas, o servidor no deve estar executando quando voc mover o diretrio
do banco de dados.)
Note que devido a penalidade que voc tem na velocidade quando abre todas as
tabelas, ns no habilitamos esta opo por padro, mesmo se voc compilar o MySQL
com suporte a isto. Para habilitar links simblicos voc deve colocar no seu arquivo
my.cnf ou my.ini a seguinte entrada:
[mysqld]
symbolic-links