Uma resposta literalmente insana, mas se você tiver algum tipo de sistema de replicação configurado (para um sistema com um bilhão de linhas, espero que sim), você pode usar um estimador aproximado (como MAX(pk)
), dividir esse valor pelo número de escravos você tem, execute várias consultas em paralelo.
Na maioria das vezes, você particionaria as consultas entre os escravos com base na melhor chave (ou na chave primária, eu acho), de tal maneira (usaremos 250000000 como nossas Linhas / escravos):
-- First slave
SELECT COUNT(pk) FROM t WHERE pk < 250000000
-- Ith slave where 2 <= I <= N - 1
SELECT COUNT(pk) FROM t WHERE pk >= I*250000000 and pk < (I+1)*250000000
-- Last slave
SELECT COUNT(pk) FROM t WHERE pk > (N-1)*250000000
Mas você precisa apenas de SQL. Que busto. Ok, então vamos dizer que você é um sadomasoquista. No mestre (ou escravo mais próximo), você provavelmente precisará criar uma tabela para isso:
CREATE TABLE counter_table (minpk integer, maxpk integer, cnt integer, slaveid integer)
Portanto, em vez de ter apenas os seletores em execução em seus escravos, você teria que fazer uma inserção, semelhante a isso:
INSERT INTO counter_table VALUES (I*25000000, (I+1)*250000000, (SELECT COUNT(pk) FROM ... ), @@SLAVE_ID)
Você pode ter problemas com os escravos escrevendo para uma tabela no mestre. Você pode precisar ficar ainda mais triste - quero dizer, criativo:
-- A table per slave!
INSERT INTO counter_table_slave_I VALUES (...)
No final, você deve ter um escravo que exista por último no caminho percorrido pelo gráfico de replicação, em relação ao primeiro escravo. Esse escravo agora deve ter todos os outros valores de contador e deve ter seus próprios valores. Porém, quando você terminar, provavelmente haverá linhas adicionadas; portanto, você deverá inserir outra para compensar o valor máximo de gravação registrado na sua counter_table e o valor máximo de atualização atual.
Nesse ponto, você teria que fazer uma função agregada para descobrir qual é o total de linhas, mas isso é mais fácil, pois você a executaria no máximo com o "número de escravos que você possui e altera".
Se você estiver na situação em que possui tabelas separadas nos escravos, poderá UNION
obter todas as linhas necessárias.
SELECT SUM(cnt) FROM (
SELECT * FROM counter_table_slave_1
UNION
SELECT * FROM counter_table_slave_2
UNION
...
)
Ou você sabe, seja um pouco menos insano e migre seus dados para um sistema de processamento distribuído, ou talvez use uma solução Data Warehousing (que também fornecerá dados impressionantes no futuro).
Observe que isso depende de quão bem sua replicação está configurada. Como o gargalo primário provavelmente será o armazenamento persistente, se você tiver armazenamento bruto ou armazenamentos de dados mal segregados com alto ruído do vizinho, provavelmente será mais lento do que apenas esperar por um únicoSELECT COUNT(*) ...
Mas se você tiver uma boa replicação, seus ganhos de velocidade deverão estar diretamente relacionados ao número ou escravos. De fato, se levar 10 minutos para executar a consulta de contagem sozinho e você tiver 8 escravos, reduzirá seu tempo para menos de alguns minutos. Talvez uma hora para resolver os detalhes desta solução.
Obviamente, você nunca obteria uma resposta incrivelmente precisa, pois essa solução distribuída introduz um pouco de tempo em que as linhas podem ser excluídas e inseridas, mas você pode tentar obter um bloqueio distribuído de linhas na mesma instância e obter uma contagem precisa das linhas da tabela por um momento específico.
Na verdade, isso parece impossível, já que você está basicamente preso a uma solução somente para SQL e não acho que tenha fornecido um mecanismo para executar uma consulta fragmentada e bloqueada em vários escravos, instantaneamente. Talvez se você tivesse o controle do arquivo de log de replicação ... o que significa que você literalmente criaria escravos para esse fim, o que é sem dúvida mais lento do que executar a consulta de contagem em uma única máquina de qualquer maneira.
Então, há meus dois centavos de 2013.