vb6 ado text-files visual-foxpro

Acelere esta operación de búsqueda/filtro-(base de datos VB6, TextFile, ADO, VFP 6.0)



text-files visual-foxpro (6)

Estoy tratando de descubrir cómo acelerar esta operación. Antes de importar un registro desde el archivo de texto, primero necesito ver si existe uno en la base de datos. Si existe, voy a realizar una operación de actualización en él. Si no existe voy a crear un nuevo registro.

Ejecutar el código que se ve debajo de esta operación toma alrededor de 3 horas.

Intenté usar el método de búsqueda de ADO y, de hecho, parece ser más lento que el método de filtro.

La base de datos es una base de datos Visual Foxpro 6. La tabla tiene un índice en el campo item_cd, pero la tabla no tiene ninguna clave principal establecida. Esto está fuera de mi control ya que no escribí el software y estoy tratando de evitar realizar cambios estructurales en la base de datos.

Hay 46652 filas en el archivo de texto y aproximadamente 650,000 registros / filas en el conjunto de registros ADO. Creo que adelgazar el conjunto de registros sería el mayor paso para solucionarlo, pero no he encontrado ninguna forma de hacerlo. Estoy tratando de evitar la creación de registros duplicados ya que no hay una clave principal, así que realmente necesito tener toda la tabla en mi conjunto de registros.

Debido a que estoy ejecutando esto en mi máquina local, parece que la operación está limitada por la potencia de la CPU. En realidad, esto podría usarse en toda la red, especialmente si puedo hacerlo más rápido.

Dim sFileToImport As String sFileToImport = Me.lstFiles.Text If sFileToImport = "" Then MsgBox "You must select a file from the listbox to import." Exit Sub End If If fConnectToDatabase = False Then Exit Sub With gXRst .CursorLocation = adUseClient .CursorType = adOpenKeyset .LockType = adLockReadOnly .Open "SELECT item_cd FROM xmsalinv ORDER BY item_cd ASC", gXCon End With Call fStartProgress("Running speed test.") Dim rstTxtFile As ADODB.Recordset Set rstTxtFile = New ADODB.Recordset Dim con As ADODB.Connection Set con = New ADODB.Connection Dim sConString As String, sSQL As String Dim lRecCount As Long, l As Long Dim s As String sConString = "DRIVER={Microsoft Text Driver (*.txt; *.csv)};Dbq=" & gsImportFolderPath & ";Extensions=asc,csv,tab,txt;Persist Security Info=False;" con.Open sConString sSQL = "SELECT * FROM [" & sFileToImport & "]" rstTxtFile.Open sSQL, con, adOpenKeyset, adLockPessimistic If Not (rstTxtFile.EOF And rstTxtFile.BOF) = True Then rstTxtFile.MoveFirst lRecCount = rstTxtFile.RecordCount Do Until rstTxtFile.EOF = True ''This code appears to actually be slower than the filter method I''m now using ''gXRst.MoveFirst ''gXRst.Find "item_cd = ''" & fPQ(Trim(rstTxtFile(0))) & "''" gXRst.Filter = "item_cd = ''" & fPQ(Trim(rstTxtFile(0))) & "''" If Not (gXRst.EOF And gXRst.BOF) = True Then s = "Item Found - " & Trim(rstTxtFile(0)) ''item found Else s = "Item Not Found - " & Trim(rstTxtFile(0)) ''Item not found found End If l = l + 1 Call subProgress(l, lRecCount, s) rstTxtFile.MoveNext Loop End If Call fEndProgress("Finished running speed test.") Cleanup: rstTxtFile.Close Set rstTxtFile = Nothing gXRst.Close


En respuesta a la publicación de Bob Riemersma, el archivo de texto no está causando los problemas de velocidad. Cambié mi código para abrir un conjunto de registros con una consulta que busca un solo elemento. Este código ahora se ejecuta en 1 minuto y 2 segundos, en comparación con las tres o cuatro horas que estuve mirando hacia otro lado.

Dim sFileToImport As String sFileToImport = Me.lstFiles.Text If sFileToImport = "" Then MsgBox "You must select a file from the listbox to import." Exit Sub End If If fConnectToDatabase = False Then Exit Sub Call fStartProgress("Running speed test.") Dim rstTxtFile As ADODB.Recordset Set rstTxtFile = New ADODB.Recordset Dim con As ADODB.Connection Set con = New ADODB.Connection Dim sConString As String, sSQL As String Dim lRecCount As Long, l As Long Dim sngQty As Single, sItemCat As String sConString = "DRIVER={Microsoft Text Driver (*.txt; *.csv)};Dbq=" & gsImportFolderPath & ";Extensions=asc,csv,tab,txt;Persist Security Info=False;" con.Open sConString sSQL = "SELECT * FROM [" & sFileToImport & "]" rstTxtFile.Open sSQL, con, adOpenKeyset, adLockPessimistic If Not (rstTxtFile.EOF And rstTxtFile.BOF) = True Then rstTxtFile.MoveFirst lRecCount = rstTxtFile.RecordCount Do Until rstTxtFile.EOF = True l = l + 1 sItemCat = fItemCat(Trim(rstTxtFile(0))) If sItemCat <> "[item not found]" Then sngQty = fItemQty(Trim(rstTxtFile(0))) End If Call subProgress(l, lRecCount, sngQty & " - " & sItemCat & " - " & rstTxtFile(0)) sngQty = 0 rstTxtFile.MoveNext Loop End If Call fEndProgress("Finished running speed test.") Cleanup: rstTxtFile.Close Set rstTxtFile = Nothing

Mis funciones:

Private Function fItemCat(sItem_cd As String) As String ''Returns blank if nothing found If sItem_cd <> "" Then With gXRstFind .CursorLocation = adUseClient .CursorType = adOpenKeyset .LockType = adLockReadOnly .Open "SELECT item_cd, ccategory FROM xmsalinv WHERE item_cd = ''" & fPQ(sItem_cd) & "''", gXCon End With If Not (gXRstFind.EOF And gXRstFind.BOF) = True Then ''An item can technically have a blank category although it never should have If gXRstFind!ccategory = "" Then fItemCat = "[blank]" Else fItemCat = gXRstFind!ccategory End If Else fItemCat = "[item not found]" End If gXRstFind.Close End If End Function Private Function fIsStockItem(sItem_cd As String, Optional bConsiderItemsInStockAsStockItems As Boolean = False) As Boolean If sItem_cd <> "" Then With gXRstFind .CursorLocation = adUseClient .CursorType = adOpenKeyset .LockType = adLockReadOnly .Open "SELECT item_cd, bal_qty, sug_qty FROM xmsalinv WHERE item_cd = ''" & fPQ(sItem_cd) & "''", gXCon End With If Not (gXRstFind.EOF And gXRstFind.BOF) = True Then If gXRstFind!sug_qty > 0 Then fIsStockItem = True Else If bConsiderItemsInStockAsStockItems = True Then If gXRstFind!bal_qty > 0 Then fIsStockItem = True End If End If End If End If gXRstFind.Close End If End Function Private Function fItemQty(sItem_cd As String) As Single ''Returns 0 if nothing found If sItem_cd <> "" Then With gXRstFind .CursorLocation = adUseClient .CursorType = adOpenKeyset .LockType = adLockReadOnly .Open "SELECT item_cd, bal_qty FROM xmsalinv WHERE item_cd = ''" & fPQ(sItem_cd) & "''", gXCon End With If Not (gXRstFind.EOF And gXRstFind.BOF) = True Then fItemQty = CSng(gXRstFind!bal_qty) End If gXRstFind.Close End If End Function


Utilice un cursor firehose para los resultados de la consulta de VFP si no es así, y consulte su otra publicación aquí para obtener sugerencias sobre el conjunto de registros de archivo de texto.

Sin embargo, tal vez aún mejor, podrías intentar deshacerte de tu lento enfoque de "bucle y búsqueda".

Probablemente crearía un MDB Jet 4.0 temporal desde cero para cada archivo de texto que quiera buscar. Importe los datos de texto, indexe su campo clave. Use ADOX para definir una tabla vinculada en la base de datos de VFP. El uso de una consulta para hacer su coincidencia.

Cierre y deseche el MDB después.


Primero, intente crear un índice en memoria en item_cd con gXRst!item_cd.Properties("OPTIMIZE").Value = True que acelerará tanto Find como Filter .

Para obtener la máxima velocidad en la búsqueda, inicialice el índice de ayudante Collection como esta

Set cIndex = New Collection On Error Resume Next Do While Not gXRst.EOF cIndex.Add gXRst.Bookmark, "#" & gXRst!item_cd.Value gXRst.MoveNext Loop On Error GoTo ErrorHandler

E insertada de Find usa alguna función como esta

Public Function SearchCollection(Col As Object, Index As Variant) As Boolean On Error Resume Next IsObject Col(Index) SearchCollection = (Err.Number = 0) On Error GoTo 0 End Function


Una solución simple para acelerar la respuesta de Yours_Rs.find es usar primero la declaración Yours_Rs.move si es posible para usted. Lo que he hecho es usar la declaración MyRs.move antes de usar MyRs.find para acercarme a mi registro actual. Realmente me había funcionado ya que la respuesta de move statement es bastante enérgica.

Lo estaba usando para ubicar un registro de paciente. Por lo tanto, al mover el puntero a un registro cerca del registro real, la instrucción MyRs.find funciona con la velocidad de la luz.

Saludos,

MAS.


no responde su pregunta y este es un hilo muy antiguo, pero ¿por qué no importa su archivo de texto a una tabla temporal en su base de datos y luego hace una combinación? algo así como SELECT tt. * FROM texttemp tt left outer join xmsalinv xal en tt.field1 = xal.item_cd donde xal.item_cd es nulo

esto debería devolver el contenido de su archivo de texto importado que no tiene ninguna coincidencia item_cd en la base de datos, ya que se trata de un archivo de texto que complica la consulta y es por eso que me pregunto si no va a importar el contenido a un archivo temporal mesa.

ahora suponiendo que conozca el mapeo de los campos, probablemente también pueda usar esto para insertar asumiendo que su base de datos acepte insertar notación de selección que sería insertar en xmsalinv (campos) seleccionar (campos coincidentes) desde (como arriba ...) esto se mueve su estrangulamiento apunta al proceso de importación, que espero sea rápido.

las colecciones de ado parecen ser bastante estúpidas, por lo que no se benefician de ningún tipo de conocimiento sobre los datos y son un poco lentos.

ah siguiente artículo en "filtro vb6" google http://www.techrepublic.com/article/why-ados-find-method-is-the-devil/1045830

esta respuesta se basa en conocimientos básicos de sql y no está adaptada a foxpro


3 horas solo por unos cientos de miles de discos !!! Lo estás haciendo de la manera incorrecta. Simplemente: -aplique el archivo de texto en una tabla de VFP, luego inserte los que no existen en la tabla existente con un único SQL y actualice los que existen con otra actualización de SQL.

Eso es todo y debería tomar menos de un minuto (un minuto es incluso muy lento). Puede hacer todo esto usando el controlador VFPOLEDB y no importa que tenga una base de datos VFP6, VFPOLEDB tiene el motor VFP9 incorporado.