24. januar 2007 - 15:34Der er
26 kommentarer og 2 løsninger
Indsæt rækker hurtigt i sql server
Hejsa
PT. har jeg følgende statement som udføres for at indsætte rækker i sql server.
Dim dbConnection As System.Data.SqlClient.SqlConnection = New System.Data.SqlClient.SqlConnection(sqlConnection)
Dim queryString As String = SQL Dim dbCommand As System.Data.IDbCommand = New System.Data.SqlClient.SqlCommand dbCommand.CommandText = queryString dbCommand.Connection = dbConnection
Dim rowsAffected As Integer = 0 dbConnection.Open() Try rowsAffected = dbCommand.ExecuteNonQuery Finally dbConnection.Close() End Try
Return rowsAffected
Mit problem er, at jeg indsætter mange rækker (over 10000) og det med at åbne og lukke dbconnection for hver insert er jo fjoget. Men hvordan omskriver jeg den, så jeg kun behøves at åbne adgangen en gang og så lukke den til sidst. Og kan man committe data løbende (eller er det ikke nødvendigt)
Jeg har også tænkt at flytte dbConnection op så den sker i starten. Men hvordan omskriver jeg ovenstånde statement, så den kan udføres hurtigt. Er nybeg. indenfor .net, gammel asp mand.
Sad og skimmede lidt i linket og det virker da ikke spor utænkeligt, at det vil være smart. Men det ændrer desværre ikke på, at jeg ikke aner hvordan man så vil gøre det :)
Private Shared connection As OleDbConnection() Private Shared command As OleDbCommand() Private Shared reader As OleDbDataReader() Private Shared database As Database() = Nothing
Private Sub New() Dim connection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Documents and Settings\bwa\Desktop\WebSite1\App_Data\db.mdb") 'åben connection?? End Sub
Public Shared Function GetDbInstance() As Database() If database Is Nothing Then Dim database = New Database() End If Return database End Function
Public Function AddText(ByVal sql As String) As Boolean ' her kan du så have din sql som indsætter i db'en.. metode returnere true hvis det går godt. End Function
så fjerner du ALT database fra dine øvrige sider.. og flytter metoderne herind i denne klasse.
for at oprette en instans af klassen skal du først lave en variabel af den og så burde du kunne kalde metoden GetDbInstance som gerne skulle forestille at være static.. dvs. man kan kalde den selv om objektet ikke er oprettet..
Et vn eksempel: Dim connectionString As String connectionString = " YourConnectionStringandInitial Catalog=TestSMODatabase" ' Using Dim connection As SqlConnection = New SqlConnection(connectionString) Try connection.Open ' Using Dim bulkcopy As SqlBulkCopy = New SqlBulkCopy(connection) Try bulkcopy.DestinationTableName = "dbo.TestTable" Try bulkcopy.WriteToServer(dindatatable) Catch ex As Exception Console.WriteLine(ex.Message) End Try connection.Close Finally CType(bulkcopy, IDisposable).Dispose() End Try Finally CType(connection, IDisposable).Dispose() End Try
aaben connection lav command objevt med parameters begin transactiion for alt som skal indsaettes: saet values af parameters execute non query commit transaction close connection
de 3 key elements er: - kun en connection - kun en command (hvor man saetter forskellige values for parameters) - kun en transaction
Det tog lidt tid at svare, men vil jo lige afprøve de variationer først.
Den hurtigste jeg er kommet frem til, er klart bulkimporten, selvom jeg var lidt bekymret for at opbygge store datatabeller som ville tærre hårdt på hukommelsen (og det gør det nu også).
Har brugt følgende kodestump, hvor jeg som forsøg har prøvet at indlæse 1,2 mio logfilsrækker, det tager så'n cirka 1,5-2 minutter. For at minimere hukommelsesforbruget laver jeg en bulkimport pr. 10.000 rækker og det får jeg så nedenstående resultat med. Jeg ved godt det kan laves kønnere :) men kan det laves mere effektivt?
OpbygDatatable() Dim connection As SqlConnection Dim bulkcopy As SqlBulkCopy Dim connectionString As String connectionString = "Opbygges her"
FileName = "C:\logdata.txt" Dim iTaeller As Integer = 0
Dim row As DataRow Dim objStreamReader As StreamReader objStreamReader = File.OpenText(FileName)
Dim dataRecord As String, slut As Boolean Dim logsplit As Array Do Until objStreamReader.EndOfStream Or slut = True dataRecord = objStreamReader.ReadLine()
If Len(dataRecord) > 0 Then logsplit = Split(dataRecord, " ")
iTaeller = iTaeller + 1 End If If iTaeller mod 10000 = 0 Then connection = New SqlConnection(connectionString) Try connection.Open() ' Using bulkcopy = New SqlBulkCopy(connection) Try bulkcopy.DestinationTableName = "dbo.Inlogdata" Try bulkcopy.WriteToServer(dataTable) Catch ex As Exception Console.WriteLine(ex.Message) End Try connection.Close() Finally CType(bulkcopy, IDisposable).Dispose() End Try Finally CType(connection, IDisposable).Dispose() End Try
'Fjernet datatabellen helt for at sikre den ikke ligger og flyder CType(dataTable, IDisposable).Dispose()
'Genererer dataarrayet OpbygDatatable() End If Loop objStreamReader.Close()
connection = New SqlConnection(connectionString) Try connection.Open() bulkcopy = New SqlBulkCopy(connection) Try bulkcopy.DestinationTableName = "dbo.Inlogdata" Try bulkcopy.WriteToServer(dataTable) Catch ex As Exception Console.WriteLine(ex.Message) End Try connection.Close() Finally CType(bulkcopy, IDisposable).Dispose() End Try Finally CType(connection, IDisposable).Dispose() End Try
Har også selv kigget lidt rundt og heller ikke fundet mere at optimere på. Vil bare lige være sikker på at jeg ikke glemmer at fjerne en variabel el. lign.
Får brug for at køre scriptet med flere forskellige inputs. En af typerne er ovenstående logfiler, hvor jeg hver gang skal den indlæse ml. 500.000 og 2.000.000 rækker. Så vil lige sikre at det er ret optimalt :)
Så hvis du og kalp lige vil give et svar, så vi kan afslutte det her ordentligt.
np og svar :) Det eneste du måske kan gøre er at implementerer en form for idatareader som læser fra din text fil og sender det til bulk copy. Men jeg ved ikke hvordan den skal laves :)
dcasso >> Der var ikke noget galt:) bare for sjov he he:)
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.