Avatar billede dcasso Nybegynder
24. januar 2007 - 15:34 Der 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)

mvh
Dennis
Avatar billede kalp Novice
24. januar 2007 - 15:39 #1
lav din connection global..

du laver jo en instans af den hver gang når den ligger der.
Avatar billede kalp Novice
24. januar 2007 - 15:42 #2
ellers lav en singleton klasse
Avatar billede dcasso Nybegynder
24. januar 2007 - 15:44 #3
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.
Avatar billede kalp Novice
24. januar 2007 - 15:45 #4
det er nok pænere at flytte forbindelsen ud i sin egen klasse.
det man kalder for singleton

http://msdn2.microsoft.com/en-us/library/ms954629.aspx
Avatar billede dcasso Nybegynder
24. januar 2007 - 15:49 #5
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 :)
Avatar billede kalp Novice
24. januar 2007 - 15:51 #6
Jeg kan godt lave et eksempel, men problemet er at det bliver i C#
Avatar billede dcasso Nybegynder
24. januar 2007 - 15:51 #7
tja, du må gerne prøve :) så må jeg jo se om jeg kan omforme det. Det går jo nok.

Er i hvert fald lettere med et c# eksempel, end uden :)
Avatar billede kalp Novice
24. januar 2007 - 15:52 #8
det er let nok at forstå.. gør det jo simpelt;o)
men prøver lige om jeg kan lave det i VB først..
Avatar billede dcasso Nybegynder
24. januar 2007 - 15:59 #9
Takker
Avatar billede kalp Novice
24. januar 2007 - 16:29 #10
okay.. jeg kan sgu ikke helt finde ud af det, men du skal lave en klasse som denne ca.


Imports Microsoft.VisualBasic
Imports System.Data.OleDb

Public Class Database

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

End Class
Avatar billede dr_chaos Nybegynder
24. januar 2007 - 16:29 #11
Avatar billede kalp Novice
24. januar 2007 - 16:30 #12
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..
Avatar billede kalp Novice
24. januar 2007 - 16:31 #13
der skal selvfølgelig laves en metode til at lukke db'en igen..
som du kan kalde når du er færdig.
Avatar billede dr_chaos Nybegynder
24. januar 2007 - 16:35 #14
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
Avatar billede arne_v Ekspert
24. januar 2007 - 16:52 #15
der er vel 3 oplagte muligheder:

1)

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

2)

som #1 bare med stored procedure

3)

bulk copy som dr chaos omtaler
Avatar billede dcasso Nybegynder
25. januar 2007 - 08:53 #16
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, " ")
       
        row = dataTable.NewRow()
        row("Date") = logsplit(0)
        row("Time") = logsplit(1)
        row("ClientIPAddress") = logsplit(2)
        row("Username") = logsplit(3)
        row("Servicename") = logsplit(4)
        row("Servername") = logsplit(5)
        row("ServerIpaddress") = logsplit(6)
        row("Serverport") = logsplit(7)
        row("Method") = logsplit(8)
        row("URIStem") = logsplit(9)
        row("URIQuery") = logsplit(10)
        row("ProtocolStatus") = logsplit(11)
        row("Win32Status") = logsplit(12)
        row("BytesSent") = logsplit(13)
        row("Bytesrecieved") = logsplit(14)
        row("TimeTaken") = logsplit(15)
        row("ProtocolVersion") = logsplit(16)
        row("Host") = logsplit(17)
        row("UserAgent") = logsplit(18)
        row("Cookie") = logsplit(19)
        row("Referer") = logsplit(20)
        dataTable.Rows.Add(row)
       
        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
       
    CType(dataTable, IDisposable).Dispose()
    OpbygDatatable()
Avatar billede dr_chaos Nybegynder
25. januar 2007 - 09:23 #17
Jeg har prøvet at undersøge det lidt og der ser ikke ud til at være hurtigere metoder via C# end den måde du gør det på.
JEg brugte denne søgning:
http://www.google.dk/search?client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&channel=s&hl=da&q=SqlBulkCopy+from+txt+file&meta=&btnG=Google-s%C3%B8gning
Avatar billede dcasso Nybegynder
25. januar 2007 - 09:31 #18
Hej dr_chaos

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.

mvh og tak for hjælpen
Dennis
Avatar billede dr_chaos Nybegynder
25. januar 2007 - 09:33 #19
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 :)
Avatar billede kalp Novice
25. januar 2007 - 09:34 #20
dcasso >> Du sender bare min portion af point samme vej til dr_chaos;-)
Avatar billede dr_chaos Nybegynder
25. januar 2007 - 09:35 #21
Du mangler jo heller ikke ligefrem :)
Det samme gælder vidst for mig :D
Avatar billede kalp Novice
25. januar 2007 - 09:37 #22
Det er jo lige det;o)
Avatar billede dcasso Nybegynder
25. januar 2007 - 09:39 #23
Kalp :) Men kan du så ikke lige sende et svar ;)
Avatar billede kalp Novice
25. januar 2007 - 09:42 #24
dr_chaos >> Jeg kaster dem efter dig en anden gang... det sker jo igen før eller siden:P
Avatar billede dcasso Nybegynder
25. januar 2007 - 09:43 #25
i får da bare 60 hver for indsatsen :) så kan i jo forblive gode venner ;)
Avatar billede dr_chaos Nybegynder
25. januar 2007 - 09:43 #26
jeg klarer mig.
Jeg er lidt mere begrænset i katagorier end dig :)
Avatar billede dr_chaos Nybegynder
25. januar 2007 - 09:44 #27
tak :)
Avatar billede kalp Novice
25. januar 2007 - 09:44 #28
dcasso >> Der var ikke noget galt:) bare for sjov he he:)
Avatar billede Ny bruger Nybegynder

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.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester