Est-ce que quelqu'un connaît le moyen le plus rapide d'obtenir des données de la table et de la table Excel (réseau VBA) à une table sur SQL 2008 sans em> à l'aide d'un utilitaire externe (I.E. BCP)?
Gardez à l'esprit que mes jeux de données sont généralement de 6500-15000 rangées et environ 150-250 colonnes; et je finis par transférer environ 20-150 d'entre eux lors d'un script de lot VBA automatisé. P>
J'ai essayé plusieurs méthodes d'obtenir de grandes quantités de données d'une table Excel (VBA) à SQL 2008. J'ai énuméré ceux ci-dessous: P>
Méthode 1. Passez la table dans la matrice VBA et envoyez une procédure stockée (ADO)
- L'envoi à SQL est lent p>
Méthode 2. Créez une charge d'enregistrement déconnecté, puis Sync.
- Envoi à SQL très lent p>
Méthode 3. Placez la table dans le tableau VBA, en boucle, bien que le tableau et concaténate (à l'aide de délimiteurs) puis envoyez à la procédure stockée.
- Envoi à SQL lent, mais plus rapide que la méthode 1 ou 2. P>
Méthode 4. Placez la table dans une matrice VBA, en boucle, bien que le tableau et concaténate (à l'aide de délimiteurs) puis placez chaque ligne avec une commande Ado Recokset .AddNew.
- Du SQL très rapide (environ 20 fois plus rapide que les méthodes 1 à 3), mais je devrai maintenant diviser ces données à l'aide d'une procédure distincte, qui ajoutera un temps d'attente significatif. P>
Méthode 5. Placez la table dans le tableau VBA, Serialize dans XML, envoyez une procédure stockée comme Varchar et spécifiez XML dans la procédure stockée.
- Du SQL incroyablement lent (environ 100 fois plus lent que les méthodes 1 ou 2) p>
Tout ce qui me manque? p>
6 Réponses :
Il n'y a pas de moyen le plus rapide, car il dépend d'un certain nombre de facteurs. Assurez-vous que les index dans SQL sont configurés et optimisés. Beaucoup d'index vont tuer des performances d'insertion / mise à jour car chaque insert devra mettre à jour l'index. Assurez-vous que vous ne faites qu'une connexion à la base de données et n'oubliez pas / fermez-la pendant l'opération. Exécutez la mise à jour lorsque le serveur est sous une charge minimale. La seule autre méthode que vous n'avez pas essayée est d'utiliser un objet de commande ADO et d'émettre une déclaration de insertion directe. Lors de l'utilisation de la méthode "addnew" de l'objet Recordset, assurez-vous d'émettre une seule commande "updatebatch" à la fin des inserts. À court de cela, le VBA ne peut fonctionner que aussi rapidement que le serveur SQL acceptant les entrées. P>
EDIT: On dirait que tu as tout essayé. Il y a aussi ce que l'on appelle le mode de récupération «enregistré en vrac» dans SQL Server, qui réduit les frais généraux d'enrichir autant au journal des transactions. Pourrait être quelque chose qui vaut la peine d'être examiné. Cela peut être gênant car il nécessite un peu de fiancé avec le modèle de récupération de base de données, mais cela pourrait être utile pour vous. P>
-Index ne sont pas un problème parce que je me charge dans une table Temp - mais merci, j'avais oublié ça. En utilisant définitivement une seule connexion. Quant à l'objet de commandement ADO, j'ai essayé cela, mais je l'ai trouvé qu'il n'était pas différent de la vitesse que de passer à un sp. Et oui, je n'ai émis qu'un seul lot ADO Update après avoir une boucle à travers l'ajout de nouveau. La nouvelle méthode .ADD était et est toujours de loin le plus rapide, mais uniquement lorsqu'elle est utilisée conjointement avec le concat - ce qui devrait être analysé plus tard.
Je vais regarder en mode de récupération enregistré en vrac.
De loin le moyen le plus rapide de le faire est via la Insert en vrac code>
. P>
Il y a quelques mises en garde. p>
insert en vrac code> et spécifiez un nom de fichier, rappelez-vous que le nom de fichier sera résolu sur la machine où SQL Server est en cours d'exécution em>). li>
- Vous devrez peut-être modifier le fichier
fieldterminator code> et rowterminator code> pour correspondre à votre CSV. LI>
ul>
Cela a pris des essais et une erreur pour que cela puisse obtenir cela initialement, mais l'augmentation de la performance était phénoménale par rapport à toutes les techniques que j'avais essayées. P>
Merci, mais BCP n'est pas une option. Je traite avec des milliers de formats sur la mouche et le BCP ne me donnait que des ennuis que suffisamment pour causer une catastrophe à chaque fois. J'ai besoin de quelque chose que je peux contrôler avec les commentaires d'erreur pendant la boucle du lot; Et cela élimine la plupart des programmes en vrac ... surtout le BCP.
Je n'ai pas réalisé BCP == insert en vrac code>. Cela dit, j'ai eu des problèmes similaires à travailler avec BCP initialement. Je ne connais pas les spécificités de votre situation, mais j'ai résolu les problèmes que j'avais en utilisant des terminaisons de rangée et de champ personnalisés et de «massage» les données lorsque je l'exporte vers CSV. J'ai essayé des variations de la plupart de ce que vous avez énuméré et que la performance ne s'est jamais rapprochée de l'insert en vrac. Je suis d'accord que l'insert en vrac est "finky" (pour le moins dire) et la rétroaction d'erreur pendant la boucle de lot est à côté de l'impossible (sans avoir recours à une sorte de kludge), mais je pense que ça vaut la peine d'être un autre look. Bonne chance!
Le code suivant transférera les milliers de données en quelques secondes seulement (2-3 secondes).
Dim sheet As Worksheet Set sheet = ThisWorkbook.Sheets("DataSheet") Dim Con As Object Dim cmd As Object Dim ServerName As String Dim level As Long Dim arr As Variant Dim row As Long Dim rowCount As Long Set Con = CreateObject("ADODB.Connection") Set cmd = CreateObject("ADODB.Command") ServerName = "192.164.1.11" 'Creating a connection Con.ConnectionString = "Provider=SQLOLEDB;" & _ "Data Source=" & ServerName & ";" & _ "Initial Catalog=Adventure;" & _ "UID=sa; PWD=123;" 'Setting provider Name Con.Provider = "Microsoft.JET.OLEDB.12.0" 'Opening connection Con.Open cmd.CommandType = 1 ' adCmdText Dim Rst As Object Set Rst = CreateObject("ADODB.Recordset") Table = "EmployeeDetails" 'This should be same as the database table name. With Rst Set .ActiveConnection = Con .Source = "SELECT * FROM " & Table .CursorLocation = 3 ' adUseClient .LockType = 4 ' adLockBatchOptimistic .CursorType = 0 ' adOpenForwardOnly .Open Dim tableFields(200) As Integer Dim rangeFields(200) As Integer Dim exportFieldsCount As Integer exportFieldsCount = 0 Dim col As Integer Dim index As Integer index = 1 For col = 1 To .Fields.Count exportFieldsCount = exportFieldsCount + 1 tableFields(exportFieldsCount) = col rangeFields(exportFieldsCount) = index index = index + 1 Next If exportFieldsCount = 0 Then ExportRangeToSQL = 1 GoTo ConnectionEnd End If endRow = ThisWorkbook.Sheets("DataSheet").Range("A65536").End(xlUp).row 'LastRow with the data. arr = ThisWorkbook.Sheets("DataSheet").Range("A1:CE" & endRow).Value 'This range selection column count should be same as database table column count. rowCount = UBound(arr, 1) Dim val As Variant For row = 1 To rowCount .AddNew For col = 1 To exportFieldsCount val = arr(row, rangeFields(col)) .Fields(tableFields(col - 1)) = val Next Next .UpdateBatch End With flag = True 'Closing RecordSet. If Rst.State = 1 Then Rst.Close End If 'Closing Connection Object. If Con.State = 1 Then Con.Close End If 'Setting empty for the RecordSet & Connection Objects Set Rst = Nothing Set Con = Nothing End Sub
Cela semble écrire des données sur Excel de SQL Server, et non l'inverse, car la question pose la question.
@ ThursdaySgeek Non, cela fait exactement quelle est la question posée.
fonctionne assez bien, d'autre part pour améliorer la vitesse, nous pouvons toujours modifier la requête: P>
à la place: Nous pouvons utiliser: Voici nous n'avons besoin que de noms de colonnes. Donc, pas besoin de maka une requête pour une table entière, qui prolonge le processus tant que de nouvelles données importées. P> source = "Sélectionnez * à partir de" & Table Code> P>
source = "Sélectionnez le top 1 * à partir de" & Table Code> P>
Autant que je me souvienne, vous pouvez créer un serveur lié au fichier Excel (tant que le serveur peut trouver le chemin; il est préférable de mettre le fichier sur le disque local du serveur), puis d'utiliser SQL pour récupérer des données de ça. p>
Avoir juste essayé quelques méthodes, je suis revenu à un seul mais rapide. Il est rapide car il fait que le serveur SQL effectue tout le travail, y compris un plan d'exécution efficace.
Je viens de construire une longue chaîne contenant un script d'instructions d'insertion. P>
Public Sub Upload() Const Tbl As String = "YourTbl" Dim InsertQuery As String, xlRow As Long, xlCol As Integer Dim DBconnection As New ADODB.Connection DBconnection.Open "Provider=SQLOLEDB.1;Password=MyPassword" & _ ";Persist Security Info=false;User ID=MyUserID" & _ ";Initial Catalog=MyDB;Data Source=MyServer" InsertQuery = "" xlRow = 2 While Cells(xlRow, 1) <> "" InsertQuery = InsertQuery & "INSERT INTO " & Tbl & " VALUES('" For xlCol = 1 To 6 'Must match the table structure InsertQuery = InsertQuery & Replace(Cells(xlRow, xlCol), "'", "''") & "', '" 'Includes mitigation for apostrophes in the data Next xlCol InsertQuery = InsertQuery & Format(Now(), "M/D/YYYY") & "')" & vbCrLf 'The last column is a date stamp, either way, don't forget to close that parenthesis xlRow = xlRow + 1 Wend DBconnection.Execute InsertQuery 'I'll leave any error trapping to you DBconnection.Close 'But do be tidy :-) Set DBconnection = Nothing End Sub