Considere a seguinte tabela:
CREATE TABLE `multiqueue` (
`ID` BIGINT(20) NOT NULL AUTO_INCREMENT,
`CustomerID` BIGINT(20) NOT NULL,
`Volume` INT(11) NOT NULL,
`Content` MEDIUMTEXT NOT NULL COLLATE 'utf8mb4_unicode_ci',
`PublishedTS` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB
;
Essa tabela funciona como uma multifila, ou seja, agrega as filas de solicitações provenientes de vários clientes (indicadas por CustomerID
), cada solicitação tendo um determinado Volume
trabalho.
Como escrever uma consulta que selecionará as N
linhas superiores da tabela, intercalando as linhas de diferentes clientes?
Se o cliente 1 envia 100 solicitações, cada uma do volume 1000, então o cliente 2 envia 20 solicitações, cada uma do volume 300, eu gostaria que a consulta não forçasse nenhum dos clientes a ficar sem respostas enquanto meu programa está ocupado lidando com as solicitações de outro cliente. Deve receber 1 solicitação do cliente 1 e 3-4 solicitações do cliente 2 na primeira busca, processá-las, depois receber mais 1 solicitação do cliente 1 e 3-4 solicitações do cliente 2 e assim por diante.
O que tentei até agora:
SET @runtot := 0;
SELECT q1.id1, q1.customerId1, q1.volume1, q1.content1, (@runtot := @runtot + q1.volume1) AS rt
FROM (
SELECT ID AS id1, CustomerID AS customerId1, Content AS content1
FROM multiqueue
ORDER BY id1
) AS q1
WHERE @runtot < 2000
Conforme descrito aqui , o código acima limita o número de itens selecionados com um total de execução de algum campo nas linhas selecionadas. No cenário acima, o cliente 2 passaria fome quando a consulta acima estiver em uso.
O banco de dados em uso é o MariaDB (versão 10.4.13, mas posso atualizar para o mais recente se necessário), embora uma solução para MySQL também deva funcionar.
Para versões recentes, você pode usar as funções da janela:
EDITAR:
Se você deseja pelo menos 1 linha para cada cliente, pode adicionar outra função de janela
ROW_NUMBER()
que enumera o resultado e usá-la em sua seleção:"Não faça fila, apenas faça." Ou seja, não se preocupe em colocar a(s) solicitação(ões) em uma(s) fila(s), desdobre um processo para trabalhar com a(s) tarefa(s). Isso deixa para o sistema operacional compartilhar recursos. E evita vários problemas que podem acontecer quando você tenta usar o MySQL como uma fila.