Maison base de données tutoriel mysql Une brève discussion sur le principe de communication de MySQL JDBC StreamResult

Une brève discussion sur le principe de communication de MySQL JDBC StreamResult

Oct 19, 2018 pm 04:33 PM
java jdbc mysql 数据库 线程

Le contenu de cet article concerne une brève discussion du principe de communication MySQL JDBC StreamResult. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Ceux qui ont utilisé MySQL JDBC pour lire de grandes quantités de données (par exemple, plus de 1 Go) doivent savoir que la mémoire est susceptible de déborder du tas Java lors de la lecture, et notre solution est déclaration . setFetchSize(Integer.MIN_VALUE) et assurez-vous que le curseur est en lecture seule et défile vers l'avant (la valeur par défaut du curseur). Vous pouvez également convertir le type en com.mysql.jdbc.StatementImpl, puis appeler sa méthode interne : activateStreamingResults(). ) De cette façon, la lecture de la mémoire de données ne se bloquera pas et l'effet obtenu par les deux est le même. Bien sûr, useCursorFetch peut également être utilisé, mais les performances des résultats de test de cette méthode sont beaucoup plus lentes que celles de StreamResult. Pourquoi ? Cet article expliquera ses principes généraux.

J'ai introduit dans certains articles et livres précédents que le code de traitement interne de MySQL JDBC est divisé en trois classes différentes à compléter, mais je n'ai jamais approfondi la relation entre la base de données et JDBC. Comment se déroule le processus de communication. entre eux. Pendant un moment, j'ai toujours pensé qu'il s'agissait d'un comportement côté serveur ou d'un comportement de coopération entre le client et le serveur, mais ce n'est pas le cas. Aujourd'hui, nous allons parler de ce qu'est ce comportement.

[Examinez d'abord la communication simple] :

La communication entre JDBC et la base de données est effectuée via Socket, nous pouvons donc traiter la base de données comme un fournisseur SocketServer Square, donc lorsque SocketServer renvoie des données (similaire au retour des jeux de résultats SQL), le processus est le suivant : Données du programme serveur (base de données) -> Kernel Socket Buffer -> Client Socket Buffer -> JDBC se trouve)

Jusqu'à présent, le JDBC que tout le monde a vu dans l'industrie informatique est : MySQL JDBC, SQL Server JDBC, PG JDBC, Oracle JDBC. Même pour les clients NoSQL : client Redis, client MongoDB, Memcached, le retour des données suit fondamentalement la même logique.

Une brève discussion sur le principe de communication de MySQL JDBC StreamResult

[Pourquoi se bloque-t-il lors de l'utilisation de MySQL JDBC pour lire directement les données par défaut ? 】

(1) L'ensemble de résultats SQL initié par le serveur MySQL génère tous les données via OutputStream, c'est-à-dire qu'il écrit les données dans le tampon de socket correspondant au Kennel local. Il s'agit d'une copie de mémoire (Memory. la copie n’est pas le sujet de cet article).

(2) Lorsque le Kennel's Buffer a des données, il renverra les données via le lien TCP (lien Socket activement initié par JDBC. À ce moment, les données seront renvoyées à la machine où JDBC). est localisé, il entrera d'abord dans la zone du chenil et entrera également dans une zone tampon.

(3) Une fois que JDBC a lancé l'opération SQL, le code Java se bloque sur l'opération inputStream.read() Lorsqu'il y a des données dans le tampon, il sera réveillé puis lira les données dans le tampon. Pour la mémoire Java, il s'agit d'une copie mémoire du côté JDBC.

(4) Ensuite, MySQL JDBC continuera à lire les données du tampon dans la mémoire Java et MySQL Server continuera à envoyer des données. Notez qu'avant que les données ne soient complètement assemblées, l'opération SQL initiée par le client ne répondra pas, ce qui signifie que cela vous donnera l'impression que le serveur MySQL n'a pas encore répondu. En fait, les données ont été envoyées localement et JDBC l'a fait. n'a pas encore renvoyé l'ensemble de résultats à l'endroit où la méthode d'exécution a été appelée le premier élément de données, mais lit en continu les données du tampon.

(5) La clé est que cet imbécile lira le contenu de la table entière dans la mémoire Java après avoir lu les données, qu'elles soient ou non stockées à la maison. Premièrement, FULL GC, La prochaine étape est la mémoire. débordement.

[Le réglage de useCursorFetch=true sur les paramètres JDBC peut résoudre le problème]

Cette solution combinée au paramètre FetchSize peut en effet résoudre le problème. Serveur MySQL que je veux Combien de données, combien de données sont nécessaires à chaque fois, le processus de communication est un peu comme ceci :

Une brève discussion sur le principe de communication de MySQL JDBC StreamResult

C'est tout comme dans nos vies, ce dont j'ai besoin, c'est d'aller au supermarché et d'acheter autant que nécessaire. Cependant, ce type d'interaction n'est pas comme les achats en ligne aujourd'hui. Vous pouvez vous faire livrer des choses à votre domicile tout en étant assis à la maison. Il faut marcher (lien réseau), ce qui signifie que cela nécessite une surcharge de temps réseau si les données contiennent 100 millions de données. , définissez FetchSize sur S'il est égal à 1 000, il y aura 100 000 communications aller-retour ; si le délai réseau est de 0,02 ms dans la même salle informatique, alors 100 000 communications ajouteront 2 secondes, ce qui n'est pas grave. Ainsi, si le temps de retard est de 2 ms dans les salles informatiques, il sera 200 secondes de plus (soit 3 minutes et 20 secondes). Si le temps de retard est de 10 à 40 ms dans les villes de Chine, alors le temps sera de 1 000 à 4 000 secondes. . Et si c'était 200 ~ 300 ms dans tous les pays ? Le temps sera plus de dix heures plus long.

Dans les calculs ici, nous n'avons pas inclus l'augmentation du nombre d'appels système, l'augmentation du nombre de contextes pour que les threads attendent et se réveillent, ni l'impact des retransmissions de paquets réseau sur les performances globales. Cela semble raisonnable, mais les performances ne sont effectivement pas très bonnes.

De plus, comme MySQL ne sait pas quand le client a fini de consommer les données et que sa table correspondante peut avoir des opérations d'écriture DML, MySQL doit créer un espace table temporaire pour stocker les données qui doivent être supprimées. Par conséquent, lorsque vous activez useCursorFetch pour lire une grande table, vous verrez plusieurs phénomènes sur MySQL :

(1) Les augmentations d'IOPS sont dues à une grande quantité de lecture d'E/S. S'il s'agit d'un disque dur ordinaire, il s'agit d'un disque dur ordinaire. peut provoquer une gigue dans l'écriture commerciale

(2) L'espace disque augmente. Cet espace temporaire peut être plus grand que la table d'origine. Si cette table occupe une grande proportion dans l'ensemble de la base de données, cela peut provoquer une écriture sur le disque de la base de données. plein, l'espace sera récupéré par MySQL après la lecture du jeu de résultats ou lorsque le client lance Result.close().

(3) Le CPU et la mémoire augmenteront d'un certain pourcentage, en fonction des capacités du CPU.

(4) Une fois que le client JDBC a lancé SQL, il attend longtemps les données de réponse SQL. Pendant ce temps, le serveur prépare les données. Cette attente est différente de la méthode JDBC d'origine consistant à n'en définir aucune. Paramètres.Il montre également l'attente.Les principes internes sont différents.Le premier continue de lire les données du tampon réseau et ne répond pas à l'entreprise.Maintenant, la base de données MySQL prépare l'espace de données temporaire et ne répond pas à JDBC.

[Données de lecture de flux]

Nous savons que la première méthode entraînera le blocage de Java, et la deuxième méthode est inefficace et a un plus grand impact sur la base de données MySQL , la réponse du client est également lente, cela ne peut que résoudre le problème, regardons maintenant la méthode de lecture Stream.

Comme mentionné précédemment, lorsque vous utilisez Statement.setFetchSize(Integer.MIN_VALUE) ou com.mysql.jdbc.StatementImpl.enableStreamingResults(), vous pouvez activer Stream pour que l'ensemble de résultats FetchSize ne puisse pas être utilisé avant de lancer. exécutez-le manuellement et assurez-vous que le curseur est FORWARD_ONLY.

Cette méthode est étonnante. Il semble que la mémoire ne soit pas bloquée, la réponse est plus rapide et l'impact sur MySQL est également plus faible. Au moins, les IOPS ne seront pas si importantes et l'utilisation du disque est également plus faible. disparu. Dans le passé, je ne voyais que du code séparé dans JDBC et je pensais qu'il s'agissait d'un autre protocole de communication entre MySQL et JDBC. Je ne savais pas qu'il s'agissait d'un "comportement du client". Oui, vous avez bien lu, c'est le client. Comportement.

Lorsqu'il lance activateStreamingResults(), il n'effectuera pratiquement aucune interaction avec le serveur. Autrement dit, le serveur renverra les données selon la méthode 1, puis le serveur poussera les données dans le tampon, et le client va Comment résister à la pression ?

Dans JDBC, lorsque vous activez le traitement de l'ensemble de résultats Stream, il ne lit pas toutes les données dans la mémoire Java en même temps, c'est-à-dire que les données de la figure 1 ne sont pas lues dans la mémoire Java en même temps. buffer lit un paquet à la fois (ce paquet peut être compris comme un tableau d'octets[] en Java). Il peut en lire autant à la fois, puis il verra s'il doit continuer à lire vers le bas pour garantir l'intégrité du paquet. données. . Le code métier est analysé en lignes basées sur les octets et utilisé par le côté métier.

Le serveur commence juste à pousser les données dans le tampon, et les données rempliront également le tampon du noyau du client lorsque les tampons des deux côtés sont pleins, un tampon sur le serveur essaie de passer via TCP lorsque le serveur commence à envoyer des données dans le tampon. les données sont envoyées au destinataire, le tampon du consommateur est également plein à ce moment-là, donc le thread de l'expéditeur sera bloqué, en attendant que l'autre partie en consomme une partie, elle peut pousser une partie des données vers. il. La connexion semble être qu'avant que les données du flux JDBC puissent être consommées, si les données du tampon sont pleines, alors le thread de MySQL envoyant les données sera bloqué, assurant ainsi un équilibre (pour cela, vous pouvez utiliser le Socket de Java pour essayer Est-ce le cas ci-dessous).

Pour le client JDBC, les données sont obtenues à chaque fois dans le tampon du noyau local, juste à une distance de la boîte à colis express de la communauté, elles sont donc naturellement plus chères que RT à chaque fois lorsqu'on se rend au supermarché. Il est beaucoup plus petit et ce processus est constitué de données préparées, il n'y a donc pas de processus de blocage des E/S (à moins que les données transmises par le serveur MySQL ne soient pas aussi rapides que le consommateur pour traiter les données, alors généralement seul le consommateur ne le fait pas. n'importe quelle entreprise et obtient Cela se produit uniquement lorsque les données sont directement supprimées dans le code de test). À ce stade, peu importe : entre les salles informatiques, entre les régions ou entre les pays, tant que le serveur commence à répondre, les données seront continuellement transmises. passée sous silence, et cette action même si elle est du premier type. La méthode est aussi un processus qui doit être vécu.

Par rapport à la première méthode, JDBC ne provoquera pas de débordement de mémoire lorsqu'il est utilisé Même si une grande table est lue sans débordement de mémoire, la réponse prendra cependant beaucoup de temps ; 1. L'impact sur la base de données est relativement important. Pendant le processus de transfert de données, les lignes de données correspondantes seront verrouillées (pour empêcher toute modification). L'utilisation d'InnoDB effectuera un traitement de verrouillage segmenté, tandis que l'utilisation de MyISAM ajoutera des verrous de table complets, ce qui peut provoquer une obstruction aux affaires.

[Théoriquement vous pouvez aller plus loin, tant que vous le souhaitez]

Théoriquement cette méthode est meilleure, mais en terme de perfectionnisme, on peut continuer Parlons-en Pour les paresseux, nous n'avons même pas la motivation d'aller à la boîte à colis express en bas de la communauté pour l'obtenir. Ce à quoi nous pensons, c'est si quelqu'un l'apporte chez moi et me le met dans la bouche, même dans. ma bouche. Ce serait génial si je la cassais.

Techniquement, cela peut effectivement être fait en théorie, car il faut du temps à JDBC pour copier la mémoire du noyau vers Java. Si une autre personne fait cela, cela ne fonctionnera pas pendant que je fais autre chose à la maison. à mon domicile. Quand j'en ai besoin, je viens directement de chez moi. Cela me fait gagner du temps. Chaque erreur est en effet enregistrée pour vous, mais la question est de savoir qui l'enverra ?

Un thread doit être ajouté au programme pour ce faire, copier les données du noyau dans la mémoire de l'application et même les analyser en lignes de données que l'application pourra utiliser directement, mais est-ce nécessairement parfait ? En fait, il y a un problème de coordination au milieu. Par exemple, si vous voulez cuisiner à la maison et qu'il vous manque un paquet d'assaisonnements, vous auriez pu les acheter vous-même en bas, mais vous devez demander à quelqu'un de les livrer. À ce moment-là, tous les autres plats sont cuits et il ne reste qu'un seul paquet d'assaisonnement, vous n'avez alors d'autre choix que d'attendre que le paquet d'assaisonnement soit livré à votre domicile avant de pouvoir procéder à la livraison. prochaine étape de la cuisson. Par conséquent, dans des circonstances idéales, cela peut permettre d'économiser beaucoup de temps de copie de la mémoire, mais augmentera la surcharge du verrouillage de coordination.

Alors, est-il possible de lire des données directement depuis le tampon du noyau ?

Théoriquement, c'est possible. Avant d'expliquer ce problème, comprenons d'abord ce qu'il y a d'autre à part cette copie mémoire :

JDBC lit les données du tampon du noyau au format binaire. Après Lors de la récupération, elles seront ensuite analysées en données structurées spécifiques, car à ce stade, les données structurées des lignes spécifiques du ResultSet doivent être renvoyées à l'entreprise, c'est-à-dire qu'il doit y avoir une copie des données générées par RowData, et JDBC renvoie certains types d'objets lorsqu'il s'agit de données (comme le tableau d'octets []), dans l'implémentation de certains scénarios, il ne souhaite pas que vous modifiiez le contenu de l'octet [] dans le résultat renvoyé (octet [1). ] = 0xFF) via l'ensemble de résultats pour modifier le contenu du ResultSet lui-même. Lors de l'utilisation du code métier, il y aura également des chaînes de caractères, une sortie réseau, etc., et il y en aura un tas. de copies de mémoire. Celles-ci sont inévitables au niveau métier. Par rapport à cette petite copie, c'est tout simplement trivial, donc nous ne l'avons pas fait, pensant que c'est presque trivial dans l'ensemble, à moins que le goulot d'étranglement de votre programme ne soit là. .

Par conséquent, la copie de mémoire est globalement inévitable. Cette fois, il ne s'agit que d'appels au niveau du système, et la surcharge sera techniquement plus importante, nous pouvons le faire directement à partir de l'état du noyau. ; mais à ce stade, les données du Buffer doivent être supprimées en fonction des octets pour permettre à davantage de données d'être transférées à distance. Il n'y a pas de troisième emplacement pour stocker le Buffer, sinon il reviendra à la copie mémoire du noyau vers. la demande.

Relativement parlant, le serveur peut optimiser et transférer des données directement via IO directe (mais le protocole de données de cette manière est cohérent avec le format de stockage des données, ce qui n'est évidemment que théorique Pour vraiment mettre en œuvre un protocole personnalisé). et envoyez des données directement via l'état du noyau, vous devez modifier le protocole du système de fichiers au niveau du système d'exploitation pour atteindre l'objectif de conversion.


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Où trouver la courte de la grue à atomide atomique
1 Il y a quelques semaines By DDD

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

La clé principale de MySQL peut être nul La clé principale de MySQL peut être nul Apr 08, 2025 pm 03:03 PM

La clé primaire MySQL ne peut pas être vide car la clé principale est un attribut de clé qui identifie de manière unique chaque ligne dans la base de données. Si la clé primaire peut être vide, l'enregistrement ne peut pas être identifié de manière unique, ce qui entraînera une confusion des données. Lorsque vous utilisez des colonnes entières ou des UUIdes auto-incrémentales comme clés principales, vous devez considérer des facteurs tels que l'efficacité et l'occupation de l'espace et choisir une solution appropriée.

Mysql peut-il renvoyer JSON Mysql peut-il renvoyer JSON Apr 08, 2025 pm 03:09 PM

MySQL peut renvoyer les données JSON. La fonction JSON_Extract extrait les valeurs de champ. Pour les requêtes complexes, envisagez d'utiliser la clause pour filtrer les données JSON, mais faites attention à son impact sur les performances. Le support de MySQL pour JSON augmente constamment, et il est recommandé de faire attention aux dernières versions et fonctionnalités.

MySQL peut-il fonctionner sur Android MySQL peut-il fonctionner sur Android Apr 08, 2025 pm 05:03 PM

MySQL ne peut pas fonctionner directement sur Android, mais il peut être implémenté indirectement en utilisant les méthodes suivantes: à l'aide de la base de données légère SQLite, qui est construite sur le système Android, ne nécessite pas de serveur distinct et a une petite utilisation des ressources, qui est très adaptée aux applications de périphériques mobiles. Connectez-vous à distance au serveur MySQL et connectez-vous à la base de données MySQL sur le serveur distant via le réseau pour la lecture et l'écriture de données, mais il existe des inconvénients tels que des dépendances de réseau solides, des problèmes de sécurité et des coûts de serveur.

L'optimisation des requêtes dans MySQL est essentielle pour améliorer les performances de la base de données, en particulier lorsqu'elle traite avec de grands ensembles de données L'optimisation des requêtes dans MySQL est essentielle pour améliorer les performances de la base de données, en particulier lorsqu'elle traite avec de grands ensembles de données Apr 08, 2025 pm 07:12 PM

1. Utilisez l'index correct pour accélérer la récupération des données en réduisant la quantité de données numérisées SELECT * FROMMLOYEESEESHWHERELAST_NAME = 'SMITH'; Si vous recherchez plusieurs fois une colonne d'une table, créez un index pour cette colonne. If you or your app needs data from multiple columns according to the criteria, create a composite index 2. Avoid select * only those required columns, if you select all unwanted columns, this will only consume more server memory and cause the server to slow down at high load or frequency times For example, your table contains columns such as created_at and updated_at and timestamps, and then avoid selecting * because they do not require inefficient query se

MySQL peut-il gérer plusieurs connexions MySQL peut-il gérer plusieurs connexions Apr 08, 2025 pm 03:51 PM

MySQL peut gérer plusieurs connexions simultanées et utiliser le multi-threading / multi-processus pour attribuer des environnements d'exécution indépendants à chaque demande client pour s'assurer qu'ils ne sont pas dérangés. Cependant, le nombre de connexions simultanées est affectée par les ressources système, la configuration MySQL, les performances de requête, le moteur de stockage et l'environnement réseau. L'optimisation nécessite la prise en compte de nombreux facteurs tels que le niveau de code (rédaction de SQL efficace), le niveau de configuration (ajustement max_connections), niveau matériel (amélioration de la configuration du serveur).

MySQL doit-il payer MySQL doit-il payer Apr 08, 2025 pm 05:36 PM

MySQL a une version communautaire gratuite et une version d'entreprise payante. La version communautaire peut être utilisée et modifiée gratuitement, mais le support est limité et convient aux applications avec des exigences de stabilité faibles et des capacités techniques solides. L'Enterprise Edition fournit une prise en charge commerciale complète pour les applications qui nécessitent une base de données stable, fiable et haute performance et disposées à payer pour le soutien. Les facteurs pris en compte lors du choix d'une version comprennent la criticité des applications, la budgétisation et les compétences techniques. Il n'y a pas d'option parfaite, seulement l'option la plus appropriée, et vous devez choisir soigneusement en fonction de la situation spécifique.

Comment optimiser les performances MySQL pour les applications de haute charge? Comment optimiser les performances MySQL pour les applications de haute charge? Apr 08, 2025 pm 06:03 PM

Guide d'optimisation des performances de la base de données MySQL dans les applications à forte intensité de ressources, la base de données MySQL joue un rôle crucial et est responsable de la gestion des transactions massives. Cependant, à mesure que l'échelle de l'application se développe, les goulots d'étranglement des performances de la base de données deviennent souvent une contrainte. Cet article explorera une série de stratégies efficaces d'optimisation des performances MySQL pour garantir que votre application reste efficace et réactive dans des charges élevées. Nous combinerons des cas réels pour expliquer les technologies clés approfondies telles que l'indexation, l'optimisation des requêtes, la conception de la base de données et la mise en cache. 1. La conception de l'architecture de la base de données et l'architecture optimisée de la base de données sont la pierre angulaire de l'optimisation des performances MySQL. Voici quelques principes de base: sélectionner le bon type de données et sélectionner le plus petit type de données qui répond aux besoins peut non seulement économiser un espace de stockage, mais également améliorer la vitesse de traitement des données.

Impossible de se connecter à MySQL en tant que racine Impossible de se connecter à MySQL en tant que racine Apr 08, 2025 pm 04:54 PM

Les principales raisons pour lesquelles vous ne pouvez pas vous connecter à MySQL en tant que racines sont des problèmes d'autorisation, des erreurs de fichier de configuration, des problèmes de mot de passe incohérents, des problèmes de fichiers de socket ou une interception de pare-feu. La solution comprend: vérifiez si le paramètre Bind-Address dans le fichier de configuration est configuré correctement. Vérifiez si les autorisations de l'utilisateur racine ont été modifiées ou supprimées et réinitialisées. Vérifiez que le mot de passe est précis, y compris les cas et les caractères spéciaux. Vérifiez les paramètres et les chemins d'autorisation du fichier de socket. Vérifiez que le pare-feu bloque les connexions au serveur MySQL.

See all articles