Mapeando Dados de um Banco de Dados Relacional

Às vezes, surgem situações em que a solução para o problema de recuperar dados de um banco de dados relacional não se encaixa nos recursos do ORM usado no projeto, por exemplo, devido à velocidade insuficiente do próprio ORM ou às consultas SQL não muito ideais geradas por ele. Nesse caso, você geralmente precisa escrever consultas manualmente.

O problema é que os dados do banco de dados (inclusive em resposta a uma solicitação JOIN) são retornados como uma matriz bidimensional "plana" que não reflete a complexa estrutura em "árvore" dos dados do aplicativo. É extremamente inconveniente trabalhar com essa matriz ainda mais, portanto, é necessária uma solução mais ou menos universal para trazer essa matriz para uma forma mais adequada, de acordo com um determinado padrão.

A solução foi encontrada, conveniente e rápido o suficiente.

Quão rápido


Para avaliar a velocidade da biblioteca, montei uma pequena bancada de testes na qual a velocidade da minha biblioteca é comparada com a velocidade do Eloquent. Para medições, foi utilizado o pacote phpbench.

Para implantar um stand em casa:

git clone https://github.com/hrustbb2/env-arrayproc-bench.git
cd env-arrayproc-bench
./env

Aqui eu usei a ferramenta descrita no meu artigo anterior .

Em seguida, no menu, selecionamos: 1 Desenvolvimento, depois: 1 Compilação, depois 2 Implementar e Ativar;
Em seguida, execute os testes 5. Execute os testes

Existem 3000 livros no banco de dados. Os resultados são os seguintes:

+-----------------+-----+------+------+-------------+--------------+
| subject         | set | revs | iter | mem_peak    | time_rev     |
+-----------------+-----+------+------+-------------+--------------+
| benchEloquent   | 0   | 1    | 0    | 76,442,912b | 12,781.612ms |
| benchEloquentId | 0   | 10   | 0    | 5,123,224b  | 16.432ms     |
| benchProc       | 0   | 1    | 0    | 36,364,176b | 1,053.937ms  |
| benchProcId     | 0   | 10   | 0    | 4,462,696b  | 7.684ms      |
+-----------------+-----+------+------+-------------+--------------+

benchEloquent - retira todos os livros com os autores usando Eloquent
benchEloquentId - retira um certo livro com os autores usando Eloquent (10 vezes)

benchProc - retira todos os livros com os autores usando a biblioteca
benchProcId - retira um determinado livro com os autores usando a biblioteca (10)

para atuar os testes não são representativos o suficiente, mas a diferença é perceptível, tanto no tempo de execução quanto no consumo de memória.

Como funciona


Instalar:

composer require hrustbb2/arrayproc:v1.0.0

Além disso, por exemplo (extremamente simples), imagine que temos um banco de dados de livros e autores com a seguinte estrutura.

imagem

A tarefa é retirar todos os livros com seus autores.

A solicitação será mais ou menos assim:

SELECT
    books.id,
    books.name,
    authors.id,
    authors.name
FROM
    books
LEFT JOIN relations ON relations.books_id = books.id
LEFT JOIN authors ON authors.id = relations.authors_id

Em resposta, obtemos essa matriz de dados.

book.idbook.nameauthor.idnome do autor
1 1book12author2
1 1book14author4
1 1book16author6
2book22author2
2book23author3
2book26author6
2book27author7


A matriz é bidimensional, alguns campos são duplicados, por conveniência, você precisa convertê-la
[
	1 => [
		'id' => 1,
		'name' => 'book1',
		'authors' => [
			2 => [
				'id' => 2,
				'name' => 'author2'
			],
			4 => [
				'id' => 4,
				'name' => 'author4'
			],
			6 => [
				'id' => 6,
				'name' => 'author6'
			],
		]
	],
	2 => [
		'id' => 2,
		'name' => 'book2',
		'authors' => [
			2 => [
				'id' => 2,
				'name' => 'author2'
			],
			3 => [
				'id' => 3,
				'name' => 'author3'
			],
			6 => [
				'id' => 6,
				'name' => 'author6'
			],
			7 => [
				'id' => 7,
				'name' => 'author7'
			],
		]
	],
]


Para fazer isso, modifique levemente nossa solicitação:


SELECT
    books.id AS book_id,
    books.name AS book_name,
    authors.id AS author_id,
    authors.name AS author_name
FROM
    books
LEFT JOIN relations ON relations.books_id = books.id
LEFT JOIN authors ON authors.id = relations.authors_id

Aqui, definimos alias na seção SELECT: para campos com dados sobre livros, alias com o prefixo 'book_' e para campos com informações sobre autores com o prefixo 'author'.

Em seguida, convertemos a resposta do banco de dados

use hrustbb2\arrayproc\ArrayProcessor;

$arrayProcessor = new ArrayProcessor();
$config = [
	'prefix' => 'book_',
	'authors' => [
		'prefix' => 'author_',
	]
]
$booksData = $arrayProcessor->process($conf, $rows)->resultArray();

onde:

$ lines é a resposta do banco de dados na forma de uma matriz de objetos / stdClass ()
$ config é uma matriz associativa que reflete a estrutura de dados da matriz resultante

Como resultado, em $ booksData, temos uma matriz em forma de árvore com a estrutura descrita em $ config, preenchida com os dados correspondentes.

Algo assim.

All Articles