Aqui está o que eu fiz e reduzi o tempo total de execução por um fator de 10.
O que percebi no plano de execução da minha consulta original foi que ela estava usando filesort para classificar todos os resultados e ignorar os índices. Isso é um pouco de desperdício.
Meu banco de dados de teste:5 M de registros, tamanho de 20 GB. estrutura da tabela igual à da pergunta
Em vez de obter blobCol diretamente na primeira consulta, primeiro obtenho o valor de 'name' para o início de cada página. Execute esta consulta indefinidamente até que ela retorne 0 resultados. Toda vez, adicione o resultado a uma lista
SELECT name
FROM my_table
where id = <anyId> // I use the id column for partitioning so I need this here
order by name
limit <pageSize * pageNumber>, 1
O número da página senoidal não é conhecido anteriormente, comece com o valor 0 e continue incrementando até que a consulta retorne nulo. Você também pode fazer um select count(*), mas isso pode levar muito tempo e não ajudará a otimizar nada. Cada consulta levou cerca de 2 segundos para ser executada quando o número da página excedeu ~60.
Para mim, o tamanho da página era 5000, então obtive uma lista de strings 'name' na posição 0, 5001, 10001, 15001 e assim por diante. O número de páginas acabou sendo 1000 e armazenar uma lista de 1000 resultados na memória não é caro.
Agora, percorra a lista e execute esta consulta
SELECT blobCol
FROM my_table
where name >= <pageHeader>
and name < <nextPageHeader>
and city="<any string>"
and id= 1
Isso será executado N vezes, onde N =tamanho da lista obtida anteriormente. Como 'nome' é a chave primária col, e 'cidade' também é indexada, EXPLAIN mostra que esse cálculo é realizado na memória usando o índice.
Agora, cada consulta leva 1 segundo para ser executada, em vez dos 30-40 originais. Assim, combinando o tempo de pré-processamento de 2 segundos por página, o tempo total por página é de 3-4 segundos em vez de 30-40.
Se alguém tiver uma solução melhor ou se houver algo gritantemente errado com este, por favor me avise