7
votes

La fonction peut-elle causer des problèmes avec les requêtes existantes?

Nous utilisons oracle 10g et oracle 11g .

Nous avons également une couche pour composer automatiquement des requêtes, du code pseudo-SQL écrit dans .NET (quelque chose comme Sqlalchemy pour Python).

Notre couche envoie actuellement n'importe quelle chaîne en guillemets simples ' et, si contient des caractères non ANSI, il compose automatiquement le désistry avec des caractères spéciaux écrits comme unicode octets (comme \ 00e0 ).

Maintenant, nous avons créé une méthode pour faire plusieurs inserts avec la construction suivante:
insérer dans ... (...) Sélectionnez ... de Dual Union Tous Sélectionnez ... de Dual ...

Cet algorithme pourrait composer des requêtes dans lesquelles le même champ de chaîne est parfois transmis comme 'ma simple chaîne' et parfois enveloppé comme unistr (ma chaîne avec des caractères spéciaux comme 00E0 ') < / code>.

La condition décrite provoque un ORA-12704: MisMatch Set de caractères .

Une solution consiste à utiliser le Insérer tout construction mais il est très lent comparé à celui utilisé maintenant.

Une autre solution consiste à instruire notre couche de mettre n devant n'importe quelle chaîne (à l'exception de ceux déjà enveloppés avec Unistr ). C'est simple.

Je veux juste savoir si cela pourrait entraîner un effet secondaire sur les requêtes existantes.

Remarque: tous nos champs sur dB sont soit NCHAR ou NVARCHAR2 .


oracle ref: http://docs.oracle.com/cd/b19306_01/ Server.102 / B14225 / CH7PROGRUNICODE.HTM


4 commentaires

Vous pouvez également lancer si vous connaissez la taille de la colonne cible. Ou votre couche peut supporter un mécanisme d'insertion en vrac approprié. Mais sûrement en utilisant n '...' évite simplement une conversion implicite du littéral lors de l'insertion, de votre jeu de caractères de base de données sur le jeu de caractères national?


@Alexpoole sincère, je ne comprends pas votre question ...


Combien de lignes sont insérées par déclaration? Si insérer tout est plus lent que Union tout Vous pouvez rencontrer un problème d'analyse Oracle, comme expliqué dans ma réponse Ici . Il peut être suffisant de casser le Insérer tout en petits morceaux pour éviter les longues fois d'analyse d'énormes déclarations SQL.


@Jonheller Pour le moment, je définissais la constante de la ligne à la ligne à 100 . Avec cette valeur, je peux obtenir 81 000 lignes (x 23 colonnes) insérées dans environ 21 secondes.


3 Réponses :


2
votes

fondamentalement ce que vous demandez est, existe-t-il une différence entre la manière dont une chaîne est stockée avec ou sans la fonction N.

Vous pouvez simplement vérifier vous-même en considérant: P>

SQL> create table test (val nvarchar2(20));

Table TEST created.

SQL> insert into test select n'test' from dual;

1 row inserted.

SQL> insert into test select 'test' from dual;

1 row inserted.

SQL> select dump(val) from test;
DUMP(VAL)                                                                      
--------------------------------------------------------------------------------
Typ=1 Len=8: 0,116,0,101,0,115,0,116                                            
Typ=1 Len=8: 0,116,0,101,0,115,0,116  


3 commentaires

Pourrait-il y avoir une décrément de performance appliquant n partout sur les littéraux string?


"Peut-il y avoir une décrément de performance appliquant n partout sur les littéraux strings?" Non, ce n'est pas parce que toute valeur de caractère insérée dans la colonne NCHAR convertie en NCHAR implicitement ou explicitement.


@Mikhailovvalentine merci. Alors, avec n , je suis juste explicit-ing un processus qui se produit implicitement de toute façon?



2
votes

Je suppose que vous obtenez une erreur "ORA-12704: MISMATCH" Parce que vos données à l'intérieur de citations considérées comme Char mais vos champs sont NCHAR, il est donc rassemblé à l'aide de différents caractères, l'utilisant < Code> nls_characterset , l'autre nls_nchar_charactterset .

Lorsque vous utilisez une fonction unistr , il convertit les données de char à < Code> nchar (dans tout cas qui convertit également les valeurs codées en caractères) comme l'oracle docs dis:

"Unistr prend comme argument un texte littéral ou une expression qui résout à des données de caractère et le renvoie dans le caractère national ensemble. "

Lorsque vous convertissez des valeurs explicitement à l'aide de N ou to_nchar Vous obtenez uniquement des valeurs dans nls_nchard_characterset sans décodage. Si vous avez des valeurs codées comme ceci "\ 00e0" ils ne seront pas décodés et seront considérés comme inchangés.

Donc, si vous avez un insert tel que: xxx

Vos données dans le premier champ d'insertion seront: 'ma chaîne avec des caractères spéciaux tels que \ 00E0' pas 'ma chaîne avec des caractères spéciaux comme à ã '. C'est le seul effet secondaire que je suis au courant. D'autres requêtes doivent déjà utiliser l'encodage NLS_NCHAR_CHARACTERSET, de sorte que cela ne devrait donc pas être un problème à l'aide d'une conversion explicite.

et d'ailleurs, pourquoi ne pas simplement insérer toutes les valeurs comme N'MY String avec des caractères spéciaux comme ã '? Il suffit de les coder dans UTF-16 (je suppose que vous utilisez UTF-16 pour NCHARS) si vous utilisez un codage différent dans le logiciel 'Upper Niveau'.


6 commentaires

"Je suppose que vous obtenez une erreur" ORA-12704: MisMatch "Parce que vos données à l'intérieur des citations considérées comme Char mais vos champs sont NCHAR" non, je reçois l'erreur parce que je mélange pas -unicode et texte unicode avec Union tout .


"Mais si vous avez des valeurs codées comme ceci" \ 00e0 ", ils ne seront pas décodés et seront considérés comme" " Les chaînes contenant des caractères spéciaux sont automatiquement enveloppées avec Unistr Par notre couche, d'autres ne le sont pas. C'est pourquoi le mélange des annonces, et c'est pourquoi j'ai besoin de N pour d'autres cordes.


"Et au fait, pourquoi ne pas simplement insérer toutes les valeurs comme N'MY String avec des caractères spéciaux tels que à '" Vous dites donc qu'il n'y a pas de différence entre utilisation Unistr ('\ 00e0') et N'à '?


"Aucune différence entre UTILISER UNISR ('\ 00E0') et N'à '" au moins lorsque j'insère à l'aide de JDBC ou de développeur SQL, je ne peux pas trouver une différence.


"Non, je reçois l'erreur parce que je mélange un texte non unicode et unicode avec l'union tout." Essayez de créer une table d'essai avec des colonnes Char et NCHAR et essayez de faire une insertion à l'aide de N'String 'pour N caractère et «chaîne» pour Char - cela fonctionnera.


Oui en effet, parce qu'ils sont deux colonnes distinctes. Dans mon cas, lors de l'utilisation de Union tout , les valeurs de chaque sous- Sélectionnez l'instruction Fusionner dans une seule colonne avant d'être insérée, elles doivent donc avoir le même ensemble de caractères.



-1
votes
  • Utilisation de N FONCTION - Vous avez déjà des réponses ci-dessus.

    Si vous avez des chances de modifier la brandon de la base de données, cela faciliterait votre vie. Je travaillais sur d'énormes systèmes de production et j'ai trouvé la tendance que, à cause de l'espace de stockage, tout le monde passe à Al32utF8 et que les soucis de l'internationalisation deviennent lentement les souvenirs douloureux du passé.

    J'ai trouvé que la chose la plus facile est d'utiliser AL32UTF8 en tant que Chart de l'instance de base de données, et utilisez simplement Varchar2 partout. Nous lisons et écrivons des chaînes Standard Java Unicode via JDBC en tant que variables liées sans préjudice, ni violon.

    Votre idée de construire un énorme texte d'inserts SQL peut ne pas bien augmenter pour plusieurs raisons:

    • Il existe une longueur fixe de l'instruction SQL maximale autorisée - elle ne fonctionnera donc pas avec 10000 inserts
    • Il est conseillé d'utiliser des variables de liaison (puis de ne pas avoir le mess de N'xxx 'vs Unistr mess non-)
    • L'idée de créer une nouvelle instruction SQL de manière dynamique est une ressource très infraction. Il ne permet pas à Oracle de mettre en cache un plan d'exécution pour quoi que ce soit et façonnera Oracle Hard analysez votre déclaration LOOONG à chaque appel.

      Qu'est-ce que vous essayez d'atteindre est un insert de masse. Utilisez le mode de lot JDBC du pilote Oracle pour effectuer cela à la vitesse de la lumière, voir par exemple: http://viralpatel.net/blogs/batch-insert-in-java-jdbc/

      Notez que la vitesse d'insertion est également affectée par des déclencheurs (qui doivent être exécutés) et des contraintes de clé étrangères (qui doivent être validées). Donc, si vous êtes sur le point d'insérer plus de quelques milliers de lignes, envisagez de désactiver les déclencheurs et des contraintes de clé étrangère et leur permettez-leur après l'insertion. (Vous perdrez les appels de déclenchement, mais la validation de contrainte après l'insertion peut avoir un impact.)

      Considérez également la taille du segment de restauration. Si vous insérez un million d'enregistrements, cela nécessitera un énorme segment de restauration, qui entraînera probablement un échange grave sur le support de stockage. C'est une bonne règle de commettre à s'engager après chaque 1000 enregistrements.

      (Oracle utilise la versioning au lieu de verrous partagés, une table avec des modifications non engagées est toujours disponible pour la lecture. Le taux de validation de 1000 enregistrements signifie environ 1 commit par seconde - assez lent pour le bénéfice des tampons d'écriture, mais suffisamment rapide pour ne pas interférer avec d'autres humains disposés à mettre à jour la même table.)


7 commentaires

"Il existe une longueur fixe de l'instruction SQL maximale autorisée - elle ne fonctionnera donc pas avec 10000 inserts" , tout simplement pas vrai. Oracle n'a pas de limite de longueur fixe , voir Stackoverflow.com/Questtions/14355819/... . BTW, notre couche scindre automatiquement la requête en taille prédéfinie. Nous n'avons donc pas besoin de vous inquiéter de telles choses.


"Ce que vous essayez d'atteindre est un insert de masse. Utilisez le mode de lot JDBC du pilote Oracle" Je sais qu'il existe des moyens d'insertion en vrac, c'est-à-dire à partir d'un fichier texte formaté, mais ceci est tout simplement pas le cas. Notre couche compose également des requêtes pour SQLServer et Postgres. BTW, personne n'a mentionné Java, nous travaillons avec .NET.


"envisagez de désactiver les déclencheurs et les contraintes de clé étrangère" nous n'avons pas de déclencheurs dans notre configuration. Quoi qu'il en soit, veuillez noter que les déclencheurs sont souvent quelque chose que vous ne pouvez pas passer sans, surtout s'ils effectuent des modifications de données.


"envisager de désactiver les déclencheurs et les contraintes de clé étrangère" Les contraintes de clé étrangère peuvent avoir une incidence sur le taux d'insertion des données, mais si vous les désactivez, vous devez les réactiver plus tard ... et la Il est temps de réactiver (et de vérifier) ​​est comparable au temps enregistré lors de l'insertion .


"Considérons également la taille du segment de restauration." Personne n'a mentionné les transactions. De toute façon ils sont là pour être utilisés. L'engagement @ 1000 records seuils, dans certaines applications, est ridicoleux.


@Teejay, je suis désolé si vous avez mal compris ma réponse. J'ai suggéré une solution beaucoup plus facile à la mondialisation que Nvarchars (qui fonctionne réellement dans n'importe quel environnement Unicode, y compris .NET) et a essayé de résoudre votre problème avec la lenteur. Si ceux-ci ne sont pas pertinents pour vous, n'hésitez pas à ignorer de la question. Pour les enregistrements, les transactions sont là tout le temps, même implicitement ou explicitement. J'ai constaté que 1000 transactions commettre sont assez standard dans le chargement en vrac des bases de données Oracle de production, que je travaille au cours des 15 dernières années.


Désolé d'interpréter mal votre réponse et de sous-estimer votre expérience. Veuillez modifier légèrement votre question afin que je puisse supprimer le bowvote (il est verrouillé). Malheureusement, la modification de l'approche n'est pas une option ici. BTW, Insérer dans ... Union Tout est assez rapide, du moins pour nos actionnements.