Slow remote mysql with VB.net- need to speed up - mysql

I'm using vb.net and mysql( from a shared hosting) with the following code
Public conn As OdbcConnection
Public da As OdbcDataAdapter
Public ds As DataSet
Public dr As OdbcDataReader
Public cmd As OdbcCommand
Public MysqlConn As MySqlConnection
Public xc As MySqlCommand
Public xd As MySqlDataAdapter
Public serv As String, user As String, pass As String, db As String
Sub connect()
serv = "xyz.com"
user = "abc"
pass = "mypasword"
db = "mydb"
MysqlConn = New MySqlConnection()
MysqlConn.ConnectionString = "server=" & serv & ";" & "UserID=" & user & ";" & "password=" & pass & ";" & "database=" & db & ";Character Set=utf8;"
Try
MysqlConn.Open()
MysqlConn.Close()
Catch myerror As Exception
MsgBox("Connection Error")
End Try
End Sub
Now any select, insert or update action takes more that 5 seconds and freezes the whole application. But my client wants it faster. How can I speed it up? is that the hosting or mysql or connection method - which is to upgrade or alter with other to make it faster?
Thanks

India:Canada -- 140ms seems reasonable. This means that every query sent to the server will take at least that long.
As for the "5 seconds"... Turn on the "General log" for a short while and run the app. Then look through the log. You may find that vb.net is injecting some extra commands, possibly in front of each query you run. This would further slow down your application. If that is the case, abandon vb.net, and be suspicious of any other 3rd party software.
I hope you are doing only one "connection" for an entire session?
Aside from that, the best thing to consider doing is to write Stored Routines (Procedures, Functions, Triggers, etc) whenever you need to perform more than one query in a row. That way, you can issue one query instead of multiple SQL statements, thereby fewer roundtrips.

Related

Speed Up Moving data from Oracle 11 to MySQL using MS Access

I have a little problem with downloading data from Oracle DB and moving it to the MySQL table.
On Oracle i have only a read privilege. The only task I could execute is Select.
On MySQL i have select/insert/update privilege. Also, there's no problem to change anything in mysql structure - i also have access to mysql root.
Each week I have to download huge amount of data from Oracle and move it to MySQL (for further processing). The best (and the only) solution in my case is to use MS Access.
My vba code snippet looks like (code is usually put into a loop, where I perform some inserts, each for different business site. Executing it in one query sometimes meet no end).
Public Sub DownloadData()
On Error GoTo ErrorTrans
DoCmd.SetWarnings False
Dim strWhere1 As String, strWhere2 As String, strQueryName As String
Dim qdDaneObrRabE As QueryDef, qdDaneObrRabTmp As QueryDef
Dim cnADO As ADODB.Connection
DoCmd.OpenQuery ("qryDaneObrRabCzysc") 'Calling truncate data procedure on mysql table
Set cnADO = CurrentProject.Connection
cnADO.CommandTimeout = 300 '5 minut
Set qdDaneObrRabE = CurrentDb.QueryDefs("qryDaneObrRabE")
strQueryName = "tmpObroty_" & GenerateHash(8)
Set qdDaneObrRabTmp = CurrentDb.CreateQueryDef(strQueryName, "select * from table2;") 'this select is just dummy statement, replaced some lines below
qdDaneObrRabTmp.Connect = qdDaneObrRabE.Connect
qdDaneObrRabTmp.SQL = Replace(qdDaneObrRabE.SQL, "{WHERE1}", strWhere1)
qdDaneObrRabTmp.SQL = Replace(qdDaneObrRabTmp.SQL, "{WHERE2}", strWhere2)
cnADO.Execute "INSERT INTO mysqltable SELECT * FROM " & strQueryName & ";"
Call QueryDefsCleanUp("tmpObroty_")
Call MsgBox("Success")
Set cnADO = Nothing
Exit Sub
ErrorTrans:
Call ActivityLog(Environ("USERNAME"), Now, "DownloadData", True, Err.Number, Err.Description)
End Sub
Please let me know if executing these types of inserts via ADODB is good.
I also tested DAO but i don't see difference.
All of used tables/querydefs are linked tables or pass-through querydefs.

Syntax Error in VBA Code - Run Time error '-2147217900(80040e14)'

I have another issue now that we have decided to move things to a server since the database cannot handle the amount of data being captured.
The short of it is:
I have tried using my existing code via transferspreadsheet method to import data to a tmp file but this is taking to long now with the SQL Server. I would like to stay with doing this programmatically and have been working with the following code. I am not sure if this will work since I can't get past the syntax error. If anyone could help it would be greatly appreciated
code start:
Dim CN As ADODB.Connection
Dim strConn As String
Dim strSQL As String
Dim strXLSource As String
Dim lngRecsaff As Long
strConn = "Driver={SQL Server};Server=logistics.companyname.com;Database=ITM;Trusted_Connection=Yes;"
Set CN = New ADODB.Connection
CN.Open strConn
strXLSource = ("C:\Users\GONZW053\Documents\My Desktop Documents\Monster Database Exports\DTPM - WDW DLR\book1.xlsx;Extended Properties= Excel 12.0")
strSQL = "INSERT INTO [tmpWDWDLR] SELECT * FROM OPENDATASOURCE('Microsoft.ACE.OLEDB.12.0','Data Source = '" & strXLSource & "')"
Debug.Print strSQL
CN.Execute strSQL, lngRecsaff, adExecuteNoRecords
Debug.Print "Records Affected: " & lngRecsaff
CN.close
Set CN = Nothing
I look forward to the help as this site and contributors have been a great source of knowledge. Thanks!
Since the Excel file is not present on the server, you can't use it in OPENROWSET or OPENDATASOURCE commands.
Using Access, however, you can use an insert query to insert data from the Excel file into SQL server:
INSERT INTO [ODBC;Driver={SQL Server};Server=logistics.companyname.com;Database=ITM;Trusted_Connection=Yes;].tmpWDWDLR
SELECT *
FROM [Sheet1$]
IN 'C:\Users\GONZW053\Documents\My Desktop Documents\Monster Database Exports\DTPM - WDW DLR\book1.xlsx'[Excel 12.0 XML;HDR=No;]
(Sheet1$ is the range from the Excel file where you're moving things from)
As far as I know, this approach has relatively little overhead. Of course, moving around large files just takes time.

Classic ASP VBScript need dropin replacement for MyConn.Execute( query )

I have a site running on ASP VBScript, and the original code never closes a DB connection. It opens connections as part of "startup" for any given page, then does whatever it does and stops -- but never explicitly closes connections. This is now causing problems where things are crashing at the web server level -- presumably from the lack of garbage collection.
So I want to make a function that acts as a drop-in replacement for all the MyConn.Execute( sqlQuery ) commands throughout the site. I've found some good candidates, but none of them seem to quite work. The most promising appears to be the code below, but when I try to actually use the recordset returned I get an error.
Function GetRS(strSQL)
'this function returns a disconnected RS
'Set some constants
Const adOpenStatic = 3
Const adUseClient = 3
Const adLockBatchOptimistic = 4
'Declare our variables
Dim oConn
Dim strSQL
Dim oRS
'Open a connection
Set oConn = Server.CreateObject("ADODB.Connection")
oConn.ConnectionString = "Driver={MySQL ODBC 5.3 Unicode Driver};Server=localhost;User=foo;Password=bar;Database=baz"
oConn.Open
'Create the Recordset object
Set oRS = Server.CreateObject("ADODB.Recordset")
oRS.CursorLocation = adUseClient
'Populate the Recordset object with a SQL query
oRS.Open strSQL, oConn, adOpenStatic, adLockBatchOptimistic
'Disconnect the Recordset
Set oRS.ActiveConnection = Nothing
'Return the Recordset
Set GetRS = oRS
'Clean up...
oConn.Close
oRS.Close
Set oConn = Nothing
Set oRS = Nothing
End Function
'call the function
strSQL = "SELECT * FROM Authors"
set RS = GetRS(strSQL)
(source: https://web.archive.org/web/20211020134116/https://www.4guysfromrolla.com/webtech/080101-1.shtml)
Here's my test code:
Set rs = GetRS( "SELECT `first_name` FROM `users` WHERE `id`=123" )
x = rs( "first_name" )
response.write x
I get the error:
ADODB.Recordset error '800a0cc1'
Item cannot be found in the collection corresponding to the requested name or ordinal.
/test.asp, line 25
Using an ordinal -- rs(0) -- returns the same error.
Looks like an empty recordset to me, but it's a legit Query that does return a record.
Does anyone know why this isn't working, or can point me to other code that will do the job? (Especially with practical usage examples, which the 4guys article lacks.)
My understanding is that a a Recordset is tied to the datasource. When you execute a query, by default, the client (your program) doesn't get the entire contents of the query, but will wait until you actually request the data. That way, you can choose a specific page size, page offset etc. to efficiently select rows from the database without transferring potentially millions of rows over the wire.
As a side-effect of this, if you close the database connection, you will no longer be able to use the Recordset. You must leave the connection open until you are done with it. In the same way, closing the Recordset itself will stop you from being able to interact with it further.
You have two options: copy the data out of the Recordset into your own variables/arrays before closing, or use a different technique to manage your connection. I'll talk about the latter option here.
There is technique which will allow you to open the DB connection once, and ensure it is closed properly by VBScript when it terminates.
Class DbConnectionManager
Private Sub Class_Initialize()
Set oConn = Server.CreateObject("ADODB.Connection")
oConn.ConnectionString = "Driver={MySQL ODBC 5.3 Unicode Driver};Server=localhost;User=foo;Password=bar;Database=baz"
oConn.Open
End Sub
Private Sub Class_Terminate()
oConn.Close
End Sub
End Class
Dim connMgr : Set connMgr = New DbConnectionManager
This code snippet is untested, but the general principle is that you start your program by defining a class and creating an instance of it. When a class instance is created, Class_Initialize is called, and when your program ends (or the instance gets removed and garbage-collected), then Class_Terminate will be called. That means oConn.Close should always be called before your program ends, even in the event of an error.
This is a very basic example of how classes work, but you could actually extend the class further and insert your Execute functions into the class itself to encapsulate the database connection details for easier maintenance. If you haven't used classes in VBScript yet but you have a basic understanding of how Object-Oriented programming works, I would highly recommend you try that.
Bonus extra: It looks like you're passing in raw SQL strings. To avoid SQL injection vulnerabilities, don't build your SQL queries dynamically. Instead, use ADO and parameters so any user-created content can be safely passed into the query without security risks. How do I run a parameterized SQL query in classic ASP? And is it secure? W3Schools also has a section on how to use ADO.

What could be causing a missing DB field on my Crystal Report at run-time?

Ladies & Gentlemen,
I have been, thus far, successful in programmatically pulling records from a MySQL database to create a crystal report from a single table. Using the code below, I'm trying to join two tables and display their matched records on the report:
Try
Dim myConnectionString As String = "Server=" & FormLogin.ComboBoxServerIP.SelectedItem & ";Port=3306;Uid=parts;Password=parts;Database=accounting;"
Dim dbConn As New MySqlConnection(myConnectionString)
Dim dbQuery As String = "SELECT * " & _
"FROM cc_master a JOIN customer b ON b.accountNumber = a.customer_accountNumber;"
Dim dbAdapter As New MySqlDataAdapter(dbQuery, dbConn)
Dim dbTable As New DataTable
dbAdapter.Fill(dbTable)
Dim report As New rptCardListAll
report.SetDataSource(dbTable)
CrystalReportViewer1.ReportSource = report
CrystalReportViewer1.Zoom(1)
Catch ex As Exception
'MsgBox(ex.Message)
End Try
The problem I'm running into now is that when the report runs at run-time, all the db records are populated on the report except for the one field that I'm pulling from the CUSTOMER table. Below is a screen shot. Notice the blank CUSTOMER NAME - this shouldn't be blank because I know for a fact there's data in that field for every record.
The query works fine when I run it directly on the DB using MySQL Workbench, so I can't figure out why the report won't pull the requested information. Any help would be appreciated, thanks.
EDIT: Screenshot showing DataSet Visualizer during debug containing the missing field (nameCOMPANY)
Good evening all,
So after hours of reading and searching the web, I've managed to arrive at or better yet, discover, a solution to my problem.
It appears that even though I'd created a DataSet within VS and used that to create my CR Report, I wasn't actually using that DataSet in code. Instead what I was doing was creating a new DataTable at run-time, filling that with my query result, and setting the report's datasource property to it.
What I should have been doing was to create an instance of my DataSet (the one I created earlier and used to design the report), fill it with my query result, and set the report's datasource property to it. This allowed CR to recognize and respect the table links/relationships I established earlier in the DataSet designer. I also learned that when using the DataAdapter with a query that returns multiple tables, the default naming convention is "Table" then "Table1" and so forth - that it was necessary to map these to the actual names of my tables in the DB.
So after applying all these lessons, I had to re-do my code as follows:
Dim report As New rptCardListAll
Dim myConnectionString As String = "Server=" & FormLogin.ComboBoxServerIP.SelectedItem & ";Port=3306;Uid=parts;Password=parts;Database=accounting;"
Dim dbConn As New MySqlConnection(myConnectionString)
Dim dbQuery As String = "SELECT * FROM cc_master; " & _
"SELECT * FROM customer;"
Dim dbAdapter As New MySqlDataAdapter(dbQuery, dbConn)
With dbAdapter
.TableMappings.Add("Table", "cc_master")
.TableMappings.Add("Table1", "customer")
End With
Try
Dim dbDataSet As New accountingDataSet
dbAdapter.Fill(dbDataSet)
report.SetDataSource(dbDataSet)
CrystalReportViewer1.ReportSource = report
CrystalReportViewer1.Zoom(1)
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.OkOnly, "An Error Has Occured....")
End Try
My report now shows the missing field "nameCOMPANY" from the customer table.
CREDIT:
I want to thank #halfer, #luchosrock, and #EvilBob22 for their assistance. Also, I give credit to the authors in the following documents:
http://developer-content.emc.com/developer/downloads/CrystalReport_ADO_Dataset.pdf
How to fill Dataset with multiple tables?

Error updating MySQL database: DUPLICATE DEFAULT ENTRY FOR PRIMARY KEY = '0'

I have a MySQL dsetup called in-out and I have written a vb.NET client program to get information from the table in the database, display it in a data grid view, and then allow to user to edit this information and update it on the server.
Right now I am hosting the server on my Gateway laptop and also connecting to it from the same laptop therefore I'm using localhost as the server name. My problem is that when I go into the program and change the information and click update, nothing happens... The information stays the same yet there is no sign of an error, syntax failure, or program crash.
I've tried running this on another computer in my house and I get the same results. I can access the information without a hitch but updating it is where I run into trouble. If there was a problem with my code it would have displayed some sort of error or asked me to debug my script, which would have made it a lot easier to solve, therefore I am certain that it has something to do with my database.
Before I got to this step, I kept getting an error when retrieving the information that said something like
DUPLICATE DEFAULT ENTRY FOR PRIMARY KEY = '0'
Which means that the columns in the table related to this error cannot have more than one default value of '0', but that's gone now... (Even though I didn't change anything)
Here is the script that will recreate my database layout. Just run it in MySQL WorkBench or MySQL Query Browser (or what ever your using to manage your SQL Database).
Here's my update code: (just in case the problem lies in my program not the database)
Private Sub cmdupdate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdupdate.Click
Dim conn As New MySqlConnection
Dim myCommand As New MySqlCommand
'#######
conn.ConnectionString = "server=" & frmLogin.txtserver.Text & ";" _
& "user id=" & frmLogin.txtusername.Text & ";" _
& "password=" & frmLogin.txtpassword.Text & ";" _
& "database=in_out"
'#######
myCommand.Connection = conn
myCommand.CommandText = "INSERT INTO event(user_id, message_id, timestamp, status, creator)" _
& "VALUES(?UserID, ?MessageID, NOW(), ?Status, ?Creator)"
myCommand.Parameters.AddWithValue("?UserID", myUserID)
myCommand.Parameters.AddWithValue("?MessageID", cbomessage.SelectedValue)
myCommand.Parameters.AddWithValue("?Status", cbostatus.SelectedItem)
myCommand.Parameters.AddWithValue("?Creator", myUserID)
Try
conn.Open()
myCommand.ExecuteNonQuery()
Catch myerror As MySqlException
MsgBox("There was an error updating the database: " & myerror.Message)
End Try
refreshStatus(dgvstatus)
End Sub
Additional Details:
OS: Windows 7 Professional x64
Software: Visual Basic 2010 Express
Server Name: 'Localhost'
SQL Manager: MySQL Workbench 5.2.34 CE
Seems that you have some sort of transaction problem going on...
try to add myCommand.Connection.Close(); after the ExecuteNonQuery()
EDIT - as per comment:
Some links to learn SQL:
http://www.w3schools.com/sql/default.asp
http://www.sqlcourse.com/index.html
http://www.sql-tutorial.net/
http://www.mysqltutorial.org/
EDIT 2:
UPDATE event SET
timestamp = NOW(),
status = ?Status
WHERE user_id = ?UserID AND message_id = ?MessageID AND creator = ?Creator;
Since there is not enough details about the data model the above UPDATE statement assumes that the columns user_id and message_id and creator together identify a row uniquely... and update the timestamp and status columns accordingly...