我使用本指南在 VS 2019 中構建了一個帶有按鈕的 ASP.NET Web 表單,該按鈕在我的 SQL 服務器上執行存盤程序,并將結果寫入 CSV 檔案以通過瀏覽器下載。
這一切都很好,除了它非常慢。
例如,它需要一個多小時才能生成一個 3.4 MB 的 CSV 檔案,其中包含 20K 行。
有什么辦法可以加快速度嗎?
這是我的代碼,因為我確實根據搜索此問題的內容對其進行了一些修改,但不幸的是,這些都沒有幫助:
Protected Sub ExportCSV(ByVal sender As Object, ByVal e As EventArgs)
Dim sqlcmd As String = "EXEC my_sp_name;"
Dim constr As String = ConfigurationManager.ConnectionStrings("CONNSTR").ConnectionString
Using con As New SqlConnection(constr)
Using cmd As New SqlCommand(sqlcmd)
Using sda As New SqlDataAdapter()
cmd.Connection = con
sda.SelectCommand = cmd
Using dt As New DataTable()
sda.Fill(dt)
Dim csv As String = String.Empty
For Each column As DataColumn In dt.Columns
csv = column.ColumnName ","
Next
csv = vbCrLf
For Each row As DataRow In dt.Rows
For Each column As DataColumn In dt.Columns
csv = row(column.ColumnName).ToString().Replace(",", ";") ","
Next
csv = vbCrLf
Next
Response.Clear()
Response.ClearHeaders()
Response.ClearContent()
Response.Buffer = True
Response.AddHeader("content-disposition", "attachment;filename=Data.csv")
Response.Charset = Encoding.UTF8.WebName
Response.ContentType = "text/csv"
Response.Output.Write(csv)
Response.Flush()
Response.End()
End Using
End Using
End Using
End Using
End Sub
我的 SQL 服務器在運行時沒有看到任何活動。我什至可以在幾秒鐘內在我的 SQL 服務器上手動執行具有相同引數的相同存盤程序。
我不知道該怎么做。因此,非常感謝任何幫助。
uj5u.com熱心網友回復:
好的,有一個簡單的解釋為什么它運行得這么慢。事實上,你可以讓這個運行速度快幾百萬倍!
首先:資料庫和索引?20,000 行沒有問題。實際上,如果您使用在垃圾箱中找到的舊計算機?它可以輕松地每秒提取 100,000 行 - 并且在沒有任何索引的情況下針對資料庫執行此操作!- 即使您應用排序和標準。
所以,不,這不是資料庫問題——你的速度非常快,實際上你需要付出一些努力才能使資料庫運行緩慢。
那么,有什么問題呢?
為什么當然是字串連接!!!!
可以這樣想:
假設你必須步行 150 英里
但是,說當你達到 100 英里?去第101英里?
好吧,你回到 1 英里,然后步行 100 英里 1 英里。
那么102英里呢?
你回到第 1 英里,然后步行 102 英里
那么103英里呢?
你回到第 1 英里,然后步行 103 英里
請注意,僅 100 到 103,您現在已經走了 300 多英里!!!
您的字串連接也發生了相同的情況。事實上,在你的字串達到大約 2000 個字符后,你會看到巨大的減速。
那么,假設您的字串現在有 500,000 個字符?
你去
MyString = MyString & "Hello"
它有什么作用?
為什么它從字符位置 1 開始,并通過 500,000 個字符運行,然后添加第二部分。
所以,這就像走路的問題!!!
順便說一句,最有趣的是有些人建議檢查資料庫速度。事實上,如果你去微軟或谷歌這樣的地方面試呢?
作為開發人員,他們會提出一大堆以您為中心的問題,以回答有關多大、多遠、多少等問題。
換句話說,他們正在尋找具有規模感的開發人員。
我的意思是,你可以步行到 1 個街區外的商店。但是10英里外呢?不,你只能在一天內實際做到這一點!!!(到商店 10 英里,回來 10 英里)。因此,您需要使用某種形式的交通工具。(你需要意識到你不能再步行去商店了——可以嗎??)。
這里發布的可愛的小問題是一個完美的例子,就是這種簡單的思考方式,為什么它運行得這么慢!
事實上,洗掉所有資料庫和所有檔案操作。
試試這個簡單的回圈:
Dim str1 As String = ""
Dim str2 As String = Space(500)
Dim t As Long = Date.Now.Ticks
Dim i As Integer
For i = 1 To 3000
str1 = str1 str2
Next
Dim td As Double = (Date.Now.Ticks - t) / 10000 / 1000
TextBox1.Text = td
那么,一個簡單的回圈到3000?
(您的計算機可以在 1 秒內完成 for/next 回圈到 10 億次!!!)
大約需要 10 秒(在慢速計算機上)。
但是,現在讓我們嘗試 6000。(但請記住,您每次都回到起點,每次您走得更遠才能到達終點)。這不是程序中的線性增長 - 而是指數級的!!!!
So, will it take 20 seconds? No, because each time, you walk back to the start, traverse all to the end, and then add the 2nd string. And each walk each time gets farther (longer) each time!!!
So, with 6000? It should take 20 seconds, right? nope!!!
We get: 48 seconds!!! -- the time increase is exponential!!!1
Now you know why those hiring firms ask the above kind of job interview questions!!! - how high, how far, how big!!! You have to be able to think in terms of these types of probelms.
So, what happens if we create new row of data, but "add" it to say an array, or even a list (which then would be easy to write out as rows to a file).
Lets now try this:
Dim str2 As String = Space(500)
Dim myList As List(Of String) = New List(Of String)
Dim t As Long = Date.Now.Ticks
Dim i As Integer
For i = 1 To 6000
myList.Add(str2)
Next
Dim td As Double = (Date.Now.Ticks - t) / 10000 / 1000
TextBox1.Text = td
Time: 0
it runs so fast, that it don't even register.
Lets go to 100,000 rows.
eg:
For i = 1 To 100000
myList.Add(str2)
Next
time: 0.005033
5 1/1000th of a second!
請注意這是多么令人驚嘆!!!!- 它不僅僅是 1000 倍,而是以 100 倍的速度運行!!!
那么,對于您的代碼?好吧,既然上面的速度非常快,那么我們可以在這里稍微偷懶一點,甚至不必創建一行并將其寫出來。因為我們正在處理 20,000 行?這么小,又是為了節省時間和簡化代碼?
我們可以在上面使用。但是,如果這是 50k 或 100k 行?那么是的,我建議主回圈執行創建行,然后將其發送到檔案中。
但是,我們可以說這樣做:(空氣代碼如下!!!)
Dim MyOutList As List(Of String) = New List(Of String)
Dim csv As String = ""
For Each column As DataColumn In dt.Columns
csv = column.ColumnName ","
Next
MyOutList.Add(csv)
For Each row As DataRow In dt.Rows
csv = ""
For Each column As DataColumn In dt.Columns
csv = row(column.ColumnName).ToString().Replace(",", ";") ","
Next
MyOutList.Add(csv)
Next
Response.Clear()
Response.ClearHeaders()
Response.ClearContent()
Response.Buffer = True
Response.AddHeader("content-disposition", "attachment;filename=Data.csv")
Response.Charset = Encoding.UTF8.WebName
Response.ContentType = "text/csv"
For Each OneLine As String In MyOutList
Response.Write(OneLine & vbCrLf)
Next
Response.Flush()
Response.End()
試試上面的方法——它會跑得更快哦!!!
并在這里發回需要多長時間!
因此,我們需要逐行處理資料庫,但不要使用我們一遍又一遍地連接的一些巨大的大字串。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/405169.html
標籤:
