Cartographie des données d'une base de données relationnelle

Parfois, des situations surviennent lorsque la solution au problème de récupération des données d'une base de données relationnelle ne correspond pas aux capacités de l'ORM utilisé dans le projet, par exemple, soit en raison de la vitesse insuffisante de l'ORM lui-même, soit de requêtes SQL pas tout à fait optimales générées par celui-ci. Dans ce cas, vous devez généralement écrire des requêtes manuellement.

Le problème est que les données de la base de données (y compris en réponse à la demande JOIN) sont renvoyées sous la forme d'un tableau bidimensionnel «plat» qui ne reflète pas la structure de données «arborescente» complexe de l'application. Il est extrêmement gênant de travailler davantage avec un tel réseau, par conséquent, une solution plus ou moins universelle est requise pour mettre ce réseau sous une forme plus appropriée selon le modèle donné.

La solution a été trouvée, pratique et assez rapide.

À quelle vitesse


Pour évaluer la vitesse de la bibliothèque, j'ai monté un petit banc de test sur lequel la vitesse de ma bibliothèque est comparée à la vitesse d'Eloquent. Pour les mesures, le paquet phpbench a été utilisé.

Pour déployer un stand à domicile:

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

Ici, j'ai utilisé l'outil décrit dans mon article précédent .

Ensuite, dans le menu, nous sélectionnons: 1 Développer, puis: 1 Build, puis 2 Deploy and Up;
Exécutez ensuite les tests 5. Exécutez les tests

Il y a 3000 livres dans la base de données. Les résultats sont les suivants:

+-----------------+-----+------+------+-------------+--------------+
| 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 - extrait tous les livres avec les auteurs utilisant Eloquent
benchEloquentId - extrait un certain livre avec les auteurs utilisant Eloquent (10 fois)

benchProc - extrait tous les livres avec les auteurs utilisant la bibliothèque
benchProcId - extrait un certain livre avec les auteurs utilisant la bibliothèque (10)

pour actionner les tests ne sont pas assez représentatifs, mais la différence est notable, à la fois en termes d'exécution et de consommation de mémoire.

Comment ça fonctionne


Installer:

composer require hrustbb2/arrayproc:v1.0.0

De plus, pour un exemple (extrêmement simple), imaginez que nous avons une base de données de livres et d'auteurs avec la structure suivante.

image

La tâche consiste à sortir tous les livres avec leurs auteurs.

La demande ressemblera à ceci:

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

En réponse, nous obtenons un tel tableau de données.

book.idbook.nameauthor.idnom de l'auteur
1livre12author2
1livre14author4
1livre16author6
2livre22author2
2livre23author3
2livre26author6
2livre27author7


Le tableau est bidimensionnel, certains champs sont dupliqués, pour plus de commodité, vous devez le convertir
[
	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'
			],
		]
	],
]


Pour ce faire, modifiez légèrement notre demande:


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

Ici, nous définissons des alias dans la section SELECT: pour les champs avec des données sur les livres, les alias avec le préfixe «book_» et pour les champs avec des informations sur les auteurs avec le préfixe «author».

Ensuite, nous convertissons la réponse de la base de données

use hrustbb2\arrayproc\ArrayProcessor;

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

où:

$ lignes est la réponse de la base de données sous la forme d'un tableau d'objets / stdClass ()
$ config est un tableau associatif reflétant la structure de données du tableau résultant.En

conséquence, dans $ booksData, nous avons un tableau arborescent ayant la structure décrite dans $ config, rempli des données correspondantes.

Quelque chose comme ça.

All Articles