Hello, how are you? I am working on a program under vb.net, under mysql, and when doing an extensive data update, it becomes very slow, around 2 - 15 minutes approximately. I clarify that this is not a DELETE COMMAND or INSERT COMMAND, that is, I do not delete records or insert, only update. The objects I use are the following:
- A datagridview called productlist, which shows all the products of the database to be edited, I clarify that the user has the possibility to instantly edit many fields, for example: increase all prices by% 10.
- Bindingsource called productdata
- A datatable named productlist, which contains the data loaded from the database
- A bindingmanagerbase called price listbinding, in order to update the changes made in the control to the DataTable
- A MySqlDataAdapter called adapter, to perform the loading and updating of the datatable data and the database
- A mysqlconnection called connection, called through the conexionstring variable, which is not shown for obvious reasons.
- 3 subroutines of which one, updatedata (), is the one that is
Call when you finish making changes to the form
The SELECT and UPDATE commands of the "adapter" are the ones that matter here, the select is perfect because the load is instantaneous, but the question is the UPDATE COMMAND, which is the following:
"UPDATE prices SET price =? predate, price2 =? price2new, cost =? new-cost, profit =? new-profit WHERE idproduct = ? new? UPDATE products Set stockminimo =? Stockminimonueva, category = IFNULL ((Select id FROM category of products WHERE name = ? categoryname), (SELECT id FROM category of products LIMIT 1)), provider = IFNULL ((Select id FROM providers WHERE name = ? providername), (SELECT id FROM suppliers LIMIT 1)), quantity = ? new quantity, name =? newname WHERE id =? idnew; "
My theory, Perform 3 queries per record, regardless of what was the parameter that was modified, that is, if only one parameter was modified, the others that are running are being processed unnecessarily.
Here the structure of the database:
Table products
CREATE TABLE 'productos' (
'id' INT(11) NOT NULL AUTO_INCREMENT,
'nombre' TEXT NOT NULL,
'tipodeproducto' INT(11) NOT NULL DEFAULT '0',
'cantidadbultocerrado' DECIMAL(11,2) NOT NULL DEFAULT '0.00',
'cantidadbultoabierto' DECIMAL(11,2) NOT NULL DEFAULT '0.00',
'especial' TINYINT(4) NOT NULL DEFAULT '0',
'ultimamodificacion' DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
'ingresosbrutos' DECIMAL(3,2) NOT NULL DEFAULT '0.00',
'categoria' INT(11) NOT NULL,
'proveedor' INT(11) NOT NULL,
'cantidad' DECIMAL(11,2) NOT NULL DEFAULT '0.00',
'stockminimo' DECIMAL(11,2) NOT NULL DEFAULT '4.00',
'precio' DECIMAL(10,2) NOT NULL DEFAULT '0.00',
'costo' DECIMAL(10,2) NOT NULL DEFAULT '0.00',
'precio2' DECIMAL(10,2) NOT NULL DEFAULT '0.00',
'pesoprecio' DECIMAL(10,2) NOT NULL DEFAULT '1.00',
'fecha' DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
'codigobarras' VARCHAR(50) NOT NULL DEFAULT '',
'imagen' BLOB NULL,
'eliminado' TINYINT(1) NOT NULL DEFAULT '0',
PRIMARY KEY ('id'),
UNIQUE INDEX 'id' ('id'),
INDEX 'eliminado' ('eliminado')
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=9031
;
Table Categories of products
CREATE TABLE 'categoriadeproductos' (
'id' INT(11) NOT NULL AUTO_INCREMENT,
'nombre' TEXT NOT NULL,
'ganancia' DECIMAL(10,2) NOT NULL DEFAULT '0.00',
PRIMARY KEY ('id')
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=5
;
Price table
CREATE TABLE 'precios' (
'id' INT(11) NOT NULL AUTO_INCREMENT,
'porcentaje' DECIMAL(4,2) NOT NULL DEFAULT '0.00',
'precio' DECIMAL(10,2) NOT NULL DEFAULT '0.00',
'precio2' DECIMAL(10,2) NOT NULL DEFAULT '0.00',
'ganancia' DECIMAL(10,2) NOT NULL DEFAULT '0.00',
'costo' DECIMAL(10,2) NOT NULL DEFAULT '0.00',
'idproducto' INT(11) NOT NULL DEFAULT '0',
'numerodepreciodelista' INT(10) NOT NULL DEFAULT '0',
'impuesto' DECIMAL(10,2) NOT NULL DEFAULT '0.00',
'ingresosbrutos' DECIMAL(10,2) NOT NULL DEFAULT '0.00',
PRIMARY KEY ('id'),
INDEX 'idproducto' ('idproducto')
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=6149
;
Provider table
CREATE TABLE 'proveedores' (
'id' INT(11) NOT NULL AUTO_INCREMENT,
'nombre' VARCHAR(50) NOT NULL DEFAULT '0',
'descripcion' TEXT NULL,
'domicilio' VARCHAR(50) NULL DEFAULT NULL,
'localidad' VARCHAR(50) NULL DEFAULT NULL,
'telefono' VARCHAR(50) NULL DEFAULT NULL,
'fax' VARCHAR(50) NULL DEFAULT NULL,
'codigo postal' VARCHAR(50) NULL DEFAULT NULL,
'contacto' VARCHAR(50) NULL DEFAULT NULL,
PRIMARY KEY ('id')
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2
;
Codecode table
CREATE TABLE 'codigobarras' (
'id' INT(11) NOT NULL AUTO_INCREMENT,
'idproducto' INT(11) NOT NULL DEFAULT '0',
'codigobarras' TEXT NOT NULL,
'idrubro' INT(11) NOT NULL DEFAULT '0',
'idpromocion' INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY ('id'),
INDEX 'idproducto' ('idproducto'),
INDEX 'idpromocion' ('idpromocion'),
INDEX 'idrubro' ('idrubro')
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=9192
;
And then the code that I use to complete the update already said:
'Declaracion de variables y objetos
public listadodeproductos As New DataGridView
Public datosdeproductos As New BindingSource
Private listadepreciosbinding As BindingManagerBase
Private listadodeproducto As New DataTable
'iniciar parametros al cargar el formulario
Private Sub ME_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
AddHandler listadeproductosbinding.BindingComplete, AddressOf BindingComplete
datosdeproductos.datasource = listadodeproducto
listadeproductosbinding = me.bindingcontext(datosdeproductos, "listadodeproductos")
listadodeproductos.DataSource = listadodeproductossource
cargardatos
End Sub
'subrutina para guardar los cambios realizados en el datagridview (listadodeproductos)
sub Actualizardatos()
datosdeproductos.EndEdit()
listadeproductosbinding.EndCurrentEdit()
listadodeproducto.GetChanges()
' abro la conexion con el servidor
Using conexion As New MySqlConnection(conexionstring)
conexion.Open()
'declaro el adaptador para realizar el cambio en la base de datos
Using adaptador As New MySqlDataAdapter
adaptador.SelectCommand = New MySqlCommand("SELECT productos.id, productos.nombre AS Nombre, categoriadeproductos.nombre AS Categoría, proveedores.nombre AS Proveedor, cantidad AS Cantidad, stockminimo AS ' Stock Mínimo ', (precios.precio) AS Precio, (precios.precio2) AS ' Precio % ', (precios.costo) AS ' P.costo ', (precios.ganancia) AS Ganancia, ultimamodificacion AS ' Fecha última modificación ', codigobarras.codigobarras AS ' Código de Barras ' FROM productos INNER JOIN precios ON precios.numerodepreciodelista = 0 AND precios.idproducto = productos.id INNER JOIN codigobarras ON codigobarras.idproducto = productos.id INNER JOIN (proveedores, categoriadeproductos) ON proveedores.id = productos.proveedor AND categoriadeproductos.id = productos.categoria WHERE productos.eliminado = 0 GROUP BY productos.id", conexion)
adaptador.UpdateCommand = New MySqlCommand("UPDATE precios SET precio = ?precionueva, precio2 = ?precio2nueva, costo = ?costonueva, ganancia = ?ganancianueva WHERE idproducto = ?idnueva; UPDATE productos Set stockminimo = ?stockminimonueva, categoria = IFNULL((Select id FROM categoriadeproductos WHERE nombre = ?nombrecategoria), (SELECT id FROM categoriadeproductos LIMIT 1)), proveedor = IFNULL((Select id FROM proveedores WHERE nombre = ?nombreproveedor), (SELECT id FROM proveedores LIMIT 1)), cantidad = ?cantidadnueva, nombre = ?nombrenuevo WHERE id = ?idnueva;", conexion)
adaptador.UpdateCommand.Parameters.Add("stockminimonueva", MySqlDbType.Decimal, 11.2, "Stock Mínimo")
adaptador.UpdateCommand.Parameters.Add("cantidadnueva", MySqlDbType.Decimal, 11.2, "cantidad")
adaptador.UpdateCommand.Parameters.Add("precionueva", MySqlDbType.Decimal, 11.2, "Precio")
adaptador.UpdateCommand.Parameters.Add("precio2nueva", MySqlDbType.Decimal, 11.2, "Precio %")
adaptador.UpdateCommand.Parameters.Add("costonueva", MySqlDbType.Decimal, 11.2, "P. costo")
adaptador.UpdateCommand.Parameters.Add("ganancianueva", MySqlDbType.Decimal, 11.2, "Ganancia")
adaptador.UpdateCommand.Parameters.Add("idnueva", MySqlDbType.Int32, 11, "id")
adaptador.UpdateCommand.Parameters.Add("nombrecategoria", MySqlDbType.Text, 0, "Categoría")
adaptador.UpdateCommand.Parameters.Add("nombreproveedor", MySqlDbType.Text, 0, "Proveedor")
adaptador.UpdateCommand.Parameters.Add("nombrenuevo", MySqlDbType.Text, 0, "Nombre")
listadodeproducto.GetChanges()
adaptador.Update(listadodeproducto)
End Using
End Using
END SUB
Sub BindingComplete(ByVal sender As Object, _
ByVal e As BindingCompleteEventArgs)
If e.BindingCompleteContext = BindingCompleteContext.DataSourceUpdate _
AndAlso e.Exception Is Nothing Then
e.Binding.BindingManagerBase.EndCurrentEdit()
End If
End Sub
'Cargar los datos de la base de datos al datatable
SUB cargardatos()
Using conexion As New MySqlConnection(conexionstring)
conexion.Open()
' declaro el adaptador para realizar el cambio en la base de datos
Using adaptador As New MySqlDataAdapter
adaptador.SelectCommand = New MySqlCommand("SELECT productos.id, productos.nombre AS Nombre, categoriadeproductos.nombre AS Categoría, proveedores.nombre AS Proveedor, cantidad AS Cantidad, stockminimo AS 'Stock Mínimo', (precios.precio) AS Precio, (precios.precio2) AS 'Precio %', (precios.costo) AS 'P. costo', (precios.ganancia) AS Ganancia, ultimamodificacion AS 'Fecha última modificación', codigobarras.codigobarras AS 'Código de Barras' FROM productos INNER JOIN precios ON precios.numerodepreciodelista = 0 AND precios.idproducto = productos.id INNER JOIN codigobarras ON codigobarras.idproducto = productos.id INNER JOIN (proveedores, categoriadeproductos) ON proveedores.id = productos.proveedor AND categoriadeproductos.id = productos.categoria WHERE productos.eliminado = 0 GROUP BY productos.id", conexion)
adaptador.Fill(listadodeproducto)
listadodeproducto.tablename = "listadodeproductos"
End Using
End Using
END sub
I hope to find some way to make a more optimal query to perform the update. PD: the only data that can be modified in the datagridview are the parameters loaded in UPDATE COMMAND, the rest is only as READ ONLY