O UPDATE consulta em suas duas perguntas anteriores ( Pergunta1 , Pergunta2 ) estão atingindo a tabela 'pessoas' por PRIMARY KEY com bloqueio no nível da linha. Foi o que afirmei na Pergunta 1 em 6 de junho de 2011 10:03
Todas as transações estão atravessando a chave PRIMARY. Como o PRIMARY é um índice clusterizado no InnoDB, a chave PRIMARY e a própria linha estão juntas. Assim, atravessar uma linha ee a PRIMARY KEY são uma e a mesma. Portanto, qualquer bloqueio de índice na PRIMARY KEY também é um bloqueio de nível de linha.
Ainda não foi considerado algo que possa atribuir lentidão aos índices: O uso de índices NÃO-UNIQUE no InnoDB. Toda pesquisa indexada no InnoDB usando índices não exclusivos também possui o ID da linha de cada linha anexada à chave não exclusiva. O rowID basicamente emina a partir do Clustered Index . A atualização de índices não exclusivos DEVE SEMPRE interagir com o índice clusterizado, MESMO SE A TABELA NÃO TEM UMA CHAVE PRIMÁRIA.
Outra coisa a se pensar é o processo de gerenciamento de nós BTREE em um índice. Às vezes, requer a divisão da página dos nós. Todas as entradas no nó BTREE de índices não exclusivos contêm campos não exclusivos, MAIS o rowID dentro do índice em cluster. Para mitigar adequadamente a divisão dessas páginas BTREE sem perturbar a integridade dos dados, a linha associada ao ID da linha deve experimentar um bloqueio de nível de linha internamente.
Se a tabela 'pessoas' tiver muitos índices não exclusivos, prepare-se para ter um grande número de páginas de índice no espaço de tabela, além de ter pequenas e minúsculas linhas de bloqueio ocultando você periodicamente.
Existe outro fator que não é tão óbvio: população-chave
Às vezes, quando um índice é preenchido, os valores-chave que compõem os índices podem ficar desequilibrados ao longo do tempo e fazer com que o MySQL Query Optimizer mude de pesquisas com chave, para verificações de índice e, finalmente, para verificações de tabela completa. Isso você não pode controlar, a menos que redesenhe a tabela com novos índices para compensar a desatenção das teclas. Por favor, forneça a estrutura da tabela para a tabela 'people', a contagem da tabela 'people' e a saída dos índices show para a tabela 'people' .
Mesmo que as consultas usem apenas a PRIMARY KEY, a desigualdade de chaves em índices não exclusivos ainda precisará do equilíbrio BTREE e da divisão da página. Esse gerenciamento do BTREE produzirá uma desaceleração notável devido a bloqueios intermitentes no nível da linha que você não pretendia que acontecesse.
ATUALIZAÇÃO 14/06/2011 22:19
Consultas da pergunta 1
UPDATE people SET company_id = 1610, name = '<name>', password = '<hash>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@yahoo.com',
phone = NULL, mobile = '<phone>', iphone_device_id = 'android:<id>-<id>',
iphone_device_time = '2011-06-06 05:35:09', last_checkin = '2011-06-06 05:24:42',
location_lat = <lat>, location_long = -<lng>, gps_strength = 3296,
picture_blob_id = 1190,
authority = 1, active = 1, date_created = '2011-04-13 20:21:20',
last_login = '2011-06-06 05:35:09', panic_mode = 0,
battery_level = NULL, battery_state = NULL WHERE people_id = 3125
UPDATE people SET company_id = 1610, name = '<name>', password = '<hash>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@yahoo.com',
phone = NULL, mobile = '<phone>', iphone_device_id = 'android:<id>-<id>-<id>-<id>',
iphone_device_time = '2011-06-06 05:24:42', last_checkin = '2011-06-06 05:35:07',
location_lat = <lat>, location_long = -<lng>, gps_strength = 3296,
picture_blob_id = 1190,
authority = 1, active = 1, date_created = '2011-04-13 20:21:20',
last_login = '2011-06-06 05:35:09', panic_mode = 0,
battery_level = NULL, battery_state = NULL WHERE people_id = 3125
Imagine a sequência em eventos
- Encontre a linha por PRIMARY KEY
- Bloquear a linha e o índice em cluster
- Criar dados MVCC para todas as colunas que estão sendo atualizadas
- Quatro colunas são indexadas (email, company_id, iphone_device_id, picture_blob_id)
- Cada índice requer gerenciamento BTREE
- No mesmo espaço de transação, as etapas 1 a 5 tentam ser repetidas na mesma linha, atualizando as mesmas colunas (enviar o mesmo por email em ambas as consultas, company_id o mesmo em ambas as consultas, picture_blob_id o mesmo em ambas as consultas, iphone_device_id diferente)
Consultas da pergunta 2
UPDATE people SET iphone_device_id=NULL
WHERE iphone_device_id='iphone:<device_id_blah>' AND people_id<>666;
UPDATE people SET company_id = 444, name = 'Dad', password = '<pass>',
temp_password = NULL, reset_password_hash = NULL, email = '<redacted>@gmail.com',
phone = NULL, mobile = NULL, iphone_device_id = 'iphone:<device_id_blah>',
iphone_device_time = '2011-06-06 19:12:29', last_checkin = '2011-06-07 02:49:47',
location_lat = <lat>, location_long = <lng>, gps_strength = 66,
picture_blob_id = 1661,
authority = 1, active = 1, date_created = '2011-03-20 19:18:34',
last_login = '2011-06-07 11:15:01', panic_mode = 0, battery_level = 0.55,
battery_state = 'unplugged' WHERE people_id = 666;
Essas duas consultas são ainda mais confusas porque a primeira consulta está atualizando tudo, exceto people_id 666. Centenas de linhas estão sendo dolorosamente bloqueadas apenas com a primeira consulta. A segunda consulta está atualizando people_id 666 executando a sequência 5 de eventos. A primeira consulta está executando as mesmas 5 sequências de eventos em todas as linhas envolvidas, exceto people_id 666, mas o índice para iphone_device_id está em um curso de interecepção com duas consultas diferentes. Alguém precisa bloquear as páginas do BTREE por ordem de chegada.
Diante desses dois pares de consultas em rota de colisão, para possivelmente bloquear as mesmas páginas BTREE em um índice, pode ser uma experiência instigante para o InnoDB ou qualquer RDBMS compatível com ACID. Portanto, uma desaceleração do índice é o destino desses pares de consultas, a menos que você possa garantir que as consultas sejam executadas com AUTOCOMMIT = 1 ou permitindo leituras sujas (embora colisões como essas tornem READ-COMMITTED e READ-UNCOMMITED um pesadelo para o MVCC).
ATUALIZAÇÃO 15/06/2011 10:29
@RedBlueThing: nas consultas da pergunta 2, a primeira consulta é uma consulta de intervalo, portanto, muitos bloqueios de linha estão sendo atingidos. Observe também que ambas as consultas estão tentando bloquear o mesmo ID de espaço 0, página 4611 n bits 152 estão sendo bloqueados na PRIMARY KEY, também conhecida como índice clusterizado.
Para garantir que seu aplicativo seja executado, no mínimo, com base na série de eventos que você espera, existem duas opções diferentes que você pode tentar:
Opção 1) Converta esta tabela para MyISAM (pelo menos em um servidor de desenvolvimento). Cada UPDATE, INSERT e DELETE imporá um bloqueio de tabela completo por ordem de chegada.
Opção 2) Tente usar o nível de isolamento SERIALIZABLE . Isso bloqueará todas as linhas pretendidas no modo COMPARTILHADO.
A sequência de eventos que você espera será interrompida ou terá êxito usando essas duas opções alternativas. Se ambas as opções falharem, será necessário examinar seu aplicativo e priorizar a ordem de execução das suas consultas. Depois de estabelecer essa prioridade, você pode simplesmente desfazer essas opções (na opção 1, volte ao InnoDB, na opção 2, volte ao nível de isolamento padrão [pare de usar SERIALIZABLE]).