DBF2SQL CONVERSION SPEED PROBLEM (SOLVED)

DBF2SQL CONVERSION SPEED PROBLEM (SOLVED)

Postby RAMESHBABU » Thu Oct 01, 2009 11:04 am

Hi All,

I started converting my existing .DBF files into MYSQL. And I am using TMysql Class for conversion.

I don't know why, for a .DBF which is having 30 Fields and 20000 records is taking almost 30 mins.
Where as In tried to conver the same .DBF with "Kleyber Derick's" DBF TO SQL Converter, it took
49 seconds.

I am using the following code. Can anybody help me where I am going wrong:

Code: Select all  Expand view


*******************************************************************************
*** FUNCTION MySqlConnect(cServer, cUser, cPassword) to Connect to MySql DB ***
*******************************************************************************

FUNCTION MySqlConnect(cServer, cUserName, cPassword)

oServer := TMySQLServer():New(ALLTRIM(cServer), ALLTRIM(cUserName), ALLTRIM(cPassword))

IF oServer:NetErr()
   lConnected := .F.
   YesNo(oServer:Error())
ELSE
   lConnected := .T.
ENDIF

RETURN lConnected

*******************************************************************************
**** FUNCTION AscToMySql(cDatabase,cServer,cUser,cPassword,oMeter1,nMeter1, ***
***                      oMeter2,nMeter2) to convert ASC to MySql Db        ***
*******************************************************************************

FUNCTION AscToMySql(cDataBase, cServer, cUserName, cPassword, cPort, oMeter1, ;
                    nMeter1, oMeter2, nMeter2, aReserved)

LOCAL aDir, aFields := {}, aField, n, cField, lFound := .F.
LOCAL cFile, aFiles1 := {}, lSelected := .F.


oStartTime:lDisColors  := .F.
oStartTime:nClrTextDis := CLR_BLUE
oStartTime:Refresh()

cCurrentTime := time()
oCurrentTime:lDisColors  := .F.
oCurrentTime:nClrTextDis := CLR_HBLUE
oCurrentTime:Refresh()

cLapsedTime := "00:00:00"
oLapsedTime:lDisColors  := .F.
oLapsedTime:nClrTextDis := CLR_GREEN
oLapsedTime:Refresh()

IF lExportDel
   SET DELETED ON
ELSE
   SET DELETED OFF
ENDIF

cUserName := ALLTRIM(cUserName)
cPassword := ALLTRIM(cPassword)

CursorWait()

IF lConnected
   IF lDeciAsFloat
      oServer:lDeciAsFloat := .T.
   ELSE
      oServer:lDeciAsFloat := .F.
   ENDIF
ENDIF

IF oServer:DBExist( ALLTRIM(cDatabase) ) = 0     // 0 Indicates that the database does not exist
   CursorWait()
   oServer:CreateDatabase( ALLTRIM(cDatabase) )
   CursorArrow()
ELSE
   IF lNewDatabase
      CursorWait()
      oServer:DeleteDatabase( ALLTRIM(cDatabase) )
      oServer:CreateDatabase( ALLTRIM(cDatabase) )
      CursorArrow()
   ENDIF
ENDIF

oServer:SelectDB( ALLTRIM(cDatabase) )

IF ASCAN(oTree:aSelected,{|x|x[2] = .T.}) >0
   lSelected := .T.
ENDIF

FOR n = 1 TO LEN(aFiles)

    * Reconnect to Server for every 10 files
    IF n % 10 = 0
       oServer:End()
       lConnected := MySqlConnect(cServer, cUserName, cPassword)
       oServer:SelectDB( ALLTRIM(cDatabase) )
    ENDIF

    IF lSelected

       IF oTree:aSelected[n,2]

          cFile := UPPER(ALLTRIM(aFiles[n-1]))

          IF ASCAN(aReserved, {|x|UPPER(ALLTRIM(x[2])) == cFile}) >0
             LOOP
          ENDIF

          USE &cFile ALIAS cFile
          aFields := DbStruct()

          IF oServer:TableExist( STRTRAN(ALLTRIM(cFile),".ASC","") ) >0
             IF lDeleteTable
                IF oServer:DeleteTable(STRTRAN(ALLTRIM(cFile),".ASC",""))
                   *YesNo("Table "+ STRTRAN(ALLTRIM(cFile),".ASC","")+" Deleted successfully")
                ELSE
                   *YesNo(oServer:Error())
                   RETURN nil //QUIT
                ENDIF
             ENDIF
          ELSE
             aFields := DbStruct()         // Load the structure of the dbf in an array
             FOR EACH aField IN aFields
                 IF HB_EnumIndex() <= 2
                    AADD( aField, .T. )    // Add a new column to the array of definitions
                                           // of the first two fields. That it indicates
                                           // that these columns are NOT NULL.
                                           // This is to be able to include them like part
                                           // of the primary key.
                 ELSE
                    EXIT
                 ENDIF
             NEXT
          ENDIF

          AADD(aFields,{"DELETED","L",1,0})
          AADD(aFields,{"RECORD_NO","N",6,0})

          IF lDeleteTable
             CursorWait()
             IF oServer:CreateTable(STRTRAN(ALLTRIM(cFile),".ASC",""), aFields, "RECORD_NO")
                *YesNo("Table : "+ STRTRAN(ALLTRIM(cFile),".ASC","")+" Created successfully")
             ELSE
                *YesNo(oServer:Error())
                CursorArrow()
                RETURN nil // QUIT
             ENDIF
          ENDIF

          CursorArrow()

          IF RECCOUNT() >0
             oMeter2:SetTotal(RecCount())
             * Table Population from .ASC file mechanism
             PopulateTableData(cDatabase, aFields, cFile, oMeter2, nMeter2)
          ELSE
             oMeter2:SetTotal(100)
             oMeter2:Set(100)
             oMeter2:Refresh()
          ENDIF
          USE
          oTree:SetCurSel(n)
       ENDIF
    ENDIF

    nMeter1 := n
    oMeter1:Set(nMeter1)
    oMeter1:Refresh()

NEXT

I tried with/without Reconnecting the server for every 10 files and creating a new querry for every 250 records.
without the expected result.

RETURN nil

*******************************************************************************
*** FUNCTION PopulateTableData(aFields,cFile,oMeter2,nMeter2) to Pupulate   ***
***          Every ASC file data in its MySql Table                       ***
*******************************************************************************

FUNCTION PopulateTableData(cDatabase, aFields, cFile, oMeter2, nMeter2)

LOCAL i, n, nCounter := 0, nPos := 1, x, cField, lFound := .F.
LOCAL cSource := "", oTable

nMeter2 := 0

cFile  := lower(STRTRAN(ALLTRIM(cFile),".ASC",""))
oTable := oServer:Query("SELECT * FROM "+ALLTRIM(cDatabase)+"."+ALLTRIM(cFile), .F. )

IF oTable:NetErr()
   YesNo(oTable:Error())
   RETURN nil
ENDIF

lDisConnect := .T.
oDisConnect:Refresh()

cFile->(DbGoTop())

DO WHILE .NOT. cFile->(EOF())

   * Create Query for every nRecsPerQuery
   IF cFile->(RECNO()) % nRecsPerQuery = 0
      IF VALTYPE(oTable) = "O"
         oTable:End()
      ENDIF
      oTable := oServer:Query("SELECT * FROM "+ALLTRIM(cDatabase)+"."+ALLTRIM(cFile), .F. )
      IF oTable:NetErr()
         YesNo(oTable:Error())
         EXIT
      ENDIF
   ENDIF

   WITH OBJECT oTable

        :GetBlankRow()

        FOR n = 1 TO LEN(aFields)-2
            oTable:FieldPut(oTable:FieldName(n),FieldGet(n))
        NEXT

        IF !oTable:Append()
           EXIT
        ENDIF

        cCurrentTime := time()
        oCurrentTime:Refresh()

        cLapsedTime := ElapTime(cStartTime, cCurrentTime)
        oLapsedTime:Refresh()

   END

   cFile->(DbSkip())

   nMeter2++
   oMeter2:Set(nMeter2)
   oMeter2:Refresh()

ENDDO

cFile->(DbCloseArea())
oTable:End()

lDisConnect := .F.
oDisConnect:Refresh()

RETURN nil

 


Thanks,

- Ramesh Babu P
Last edited by RAMESHBABU on Tue Oct 06, 2009 10:07 am, edited 1 time in total.
User avatar
RAMESHBABU
 
Posts: 624
Joined: Fri Oct 21, 2005 5:54 am
Location: Secunderabad (T.S), India

Re: DBF2SQL CONVERSION IS TAKING TOO LONG TIME

Postby dutch » Fri Oct 02, 2009 4:35 am

Dear Ramesh,

I didn't convert existing dbf to MySql file but I use TMySql for create, update and delete table in WebSite. For updating, I create table and insert from DBF file (on web). MySql table with 2000 records (on web), it take about almost 1:30 mins.

Regards,
Dutch
Regards,
Dutch

FWH 19.01 / xHarbour Simplex 1.2.3 / BCC73 / Pelles C / UEStudio
FWPPC 10.02 / Harbour for PPC (FTDN)
ADS V.9 / MySql / MariaDB
R&R 12 Infinity / Crystal Report XI R2
(Thailand)
User avatar
dutch
 
Posts: 1542
Joined: Fri Oct 07, 2005 5:56 pm
Location: Thailand

Re: DBF2SQL CONVERSION IS TAKING TOO LONG TIME

Postby RAMESHBABU » Sat Oct 03, 2009 12:44 am

Dear Dutch,

Ok. Thank you very much for your answer.

Regards,

- Ramesh Babu P
User avatar
RAMESHBABU
 
Posts: 624
Joined: Fri Oct 21, 2005 5:54 am
Location: Secunderabad (T.S), India

Re: DBF2SQL CONVERSION IS TAKING TOO LONG TIME

Postby James Bott » Sun Oct 04, 2009 10:50 am

Ramesh,

I am not an experienced SQL programmer but I did do some work with SQLite a few years ago and I found that it was writing each record update back to the disk. When I changed to using BEGIN TRANSACTION/END TRANSACTION with the entire DO WHILE loop inside, it went about 100 times faster. This technique only updated the disk after all updates to the table (recordset) were completed so there was only one disk write instead of thousands.

Perhaps there is a way to do this in your situation.

Regards,
James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: DBF2SQL CONVERSION IS TAKING TOO LONG TIME

Postby RAMESHBABU » Sun Oct 04, 2009 12:51 pm

Dear James,

Very good Idea and good reasoning too. :D

I will try it now and update the result.

Regards,

- Ramesh Babu
User avatar
RAMESHBABU
 
Posts: 624
Joined: Fri Oct 21, 2005 5:54 am
Location: Secunderabad (T.S), India

Re: DBF2SQL CONVERSION IS TAKING TOO LONG TIME

Postby nageswaragunupudi » Sun Oct 04, 2009 10:47 pm

Use 'DATA LOAD INFILE" syntax of MySql to bulk load data into my sql from flat files. Please read documentation for more details.

You may also read about the built in CSV engine of MySql 5.1 beta. You can create and read CSV files directly in MySql. You can use 'SELECT ...INTO ..' syntax to transfer data from CSV file to other tables.

LOAD DATA INFILE is the most popularly used command for importing external data into MySql.
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10625
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: DBF2SQL CONVERSION ... (CLOSED)

Postby RAMESHBABU » Tue Oct 06, 2009 9:38 am

Mr.James and Mr.Nageswara Rao,

Thank you both very much for your attention to my problem.

I took some time to go through the MYSQL documentation and as suggested by Mr.Nageswara Rao,
I have implemented the LOAD DATA INFILE command and very drastic change in the speed. My
data (600000 records) could be converted with in 1.39 secs.

Nageswara rao gaaru, thank you very much for your suggeston to read the my sql documentation.

Regards to you both

- Ramesh Babu P
User avatar
RAMESHBABU
 
Posts: 624
Joined: Fri Oct 21, 2005 5:54 am
Location: Secunderabad (T.S), India

Re: DBF2SQL CONVERSION SPEED PROBLEM (SOLVED)

Postby dutch » Tue Oct 06, 2009 4:35 pm

Dear Ramesh,

It's really fast, how to do it? I've got 1.30 minute for 900 records.

Regards,
Dutch
Regards,
Dutch

FWH 19.01 / xHarbour Simplex 1.2.3 / BCC73 / Pelles C / UEStudio
FWPPC 10.02 / Harbour for PPC (FTDN)
ADS V.9 / MySql / MariaDB
R&R 12 Infinity / Crystal Report XI R2
(Thailand)
User avatar
dutch
 
Posts: 1542
Joined: Fri Oct 07, 2005 5:56 pm
Location: Thailand

Re: DBF2SQL CONVERSION SPEED PROBLEM (SOLVED)

Postby RAMESHBABU » Wed Oct 07, 2009 10:04 am

Dear Dutch,

I built a small working sample for you. Please go through it and tell me results.

Please note just for testing you have to pass cDatabase and cDbfFile (without extension) parameters from the
command line :

SYNTAX : DBF2SQL <cDatabase>, <cTable>

Also note that this prg will not upload data from memofields and to store logical fields the table
structure for logical fields needs to be altered as CHAR(1) instead of TINYINT(1). This because,
I have used :

COPY TO (cTextFile) DELIMITED WITH TAB command.

This command will store logical values as TEXT and will ignore data from all MEMO fields.

Regards,

- Ramesh Babu P

Code: Select all  Expand view

#include "fivewin.ch"
#include "xBrowse.ch"

STATIC oServer
STATIC cReserved := " ADD ALL ALTER ANALYZE AND AS ASC ASENSITIVE AUTO_INCREMENT BDB BEFORE BERKELEYDB BETWEEN BIGINT BINARY BLOB BOTH BY CALL CASCADE CASE CHANGE CHAR CHARACTER CHECK COLLATE COLUMN COLUMNS CONDITION CONNECTION CONSTRAINT CONTINUE CREATE CROSS CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP CURSOR DATABASE DATABASES DAY_HOUR DAY_MICROSECOND DAY_MINUTE DAY_SECOND "+;
                     "DEC DECIMAL DECLARE DEFAULT DELAYED DELETE DESC DESCRIBE DETERMINISTIC DISTINCT DISTINCTROW DIV DOUBLE DROP ELSE ELSEIF ENCLOSED ESCAPED EXISTS EXIT EXPLAIN FALSE FETCH FIELDS FLOAT FOR FORCE FOREIGN FOUND FRAC_SECOND FROM FULLTEXT GRANT GROUP HAVING HIGH_PRIORITY HOUR_MICROSECOND HOUR_MINUTE HOUR_SECOND IF IGNORE IN INDEX INFILE INNER INNODB INOUT "     +;
                     "INSENSITIVE INSERT INT INTEGER INTERVAL INTO IO_THREAD IS ITERATE JOIN KEY KEYS KILL LEADING LEAVE LEFT LIKE LIMIT LINES LOAD LOCALTIME  LOCALTIMESTAMP LOCK LONG LONGBLOB LONGTEXT LOOP LOW_PRIORITY MASTER_SERVER_ID MATCH MEDIUMBLOB MEDIUMINT MEDIUMTEXT IDDLEINT MINUTE_MICROSECOND MINUTE_SECOND MOD NATURAL NOT NO_WRITE_TO_BINLOG NULL NUMERIC ON OPTIMIZE " +;
                     "OPTION OPTIONALLY OR ORDER OUT OUTER OUTFILE PRECISION PRIMARY PRIVILEGES PROCEDURE PURGE READ REAL REFERENCES REGEXP RENAME REPEAT REPLACE REQUIRE RESTRICT RETURN REVOKE RIGHT RLIKE SECOND_MICROSECOND SELECT SENSITIVE SEPARATOR SET SHOW SMALLINT SOME SONAME SPATIAL SPECIFIC SQL SQLEXCEPTION SQLSTATE SQLWARNING SQL_BIG_RESULT SQL_CALC_FOUND_ROWS "        +;
                     "SQL_SMALL_RESULT SQL_TSI_DAY QL_TSI_FRAC_SECOND SQL_TSI_HOUR SQL_TSI_MINUTE SQL_TSI_MONTH SQL_TSI_QUARTER SQL_TSI_SECOND SQL_TSI_WEEK SQL_TSI_YEAR SSL  STARTING STRAIGHT_JOIN  STRIPED TABLE TABLES TERMINATED THEN TIMESTAMPADD TIMESTAMPDIFF TINYBLOB TINYINT TINYTEXT TO RAILING TRUE UNDO UNION UNIQUE UNLOCK UNSIGNED UPDATE USAGE USE USER_RESOURCES USING "  +;
                     "UTC_DATE UTC_TIME UTC_TIMESTAMP VALUES ARBINARY VARCHAR VARCHARACTER VARYING WHEN WHERE WHILE WITH WRITE XOR YEAR_MONTH ZEROFILL "

FUNCTION main(cDatabase, cDbfFile)

LOCAL cServer      := "127.0.0.1",;
           cPort          := 3306,;
          cUserName  := "username",;
          cPassword   := "password"
LOCAL cStartTime := time()  

IF PCOUNT() < 2
   MsgInfo("SYNTAX:  Dbf2Sql <cDatabse>, <cDbfFile>"+CRLF+;
                "Without any extension to file names.")
   RETURN nil
ENDIF

IF .NOT. MySqlConnect(cServer, cUserName, cPassword)
   RETURN nil
ENDIF

IF Dbf2MySql(cDatabase, cDbfFile)
   MsgInfo("Your Table '"+ALLTRIM(cDatabase)+"."+ALLTRIM(cDbfFile)+"' has been sucessfully created and"+CRLF+;
           "Data is populated from dBase File."+CRLF+;
           "And the total time taken for conversion : "+ ElapTime(cStartTime,time()))
ENDIF

RETURN nil

*************************************************************************************************
*** FUNCTION Dbf2MySql(cDatabase, cTable) - Creation of Tables & Conversion  ***
*************************************************************************************************

FUNCTION Dbf2MySql(cDatabase, cTable)

LOCAL cApp_Path := GetModuleFileName(GetInstance()), aFields, cTextFile, cQuery, i

cApp_Path := SUBSTR(cApp_Path,1,RAT("\",cApp_Path))

IF FILE(cApp_Path+ALLTRIM(cTable)+"
.DBF")
   USE (cTable)
   * Load the structure of the dbf in an array
   aFields := DbStruct()      
   * IF Field Name is a MySql's reserved word.. save them in array and show.
   FOR i = 1 TO LEN(aFields)
       cField := "
"+ALLTRIM(UPPER(aFields[i,1]))+" "
       IF cField $ cReserved
          AADD(aReserved,{i, cDatabase, cTable, cField})
       ENDIF
   NEXT

   IF LEN(aReserved) >0
      XBROWSER aReserved TITLE "
MYSQL RESERVED WORDS USED IN "+UPPER(ALLTRIM(cTable))+".DBF AS FIELD NAMES"
      RETURN .F.
   ENDIF
 
ELSE
   MsgInfo("
Sorry. Your Input file '"+UPPER(cApp_Path+ALLTRIM(cTable))+".DBF' is not present on disk.")
   RETURN .F.
ENDIF

* MySql Database Creation
TRY
   IF oServer:DBExist( ALLTRIM(cDatabase) ) = 0     // 0 Indicates that the database does not exist
      CursorWait()
      oServer:CreateDatabase( ALLTRIM(cDatabase) )
   ELSE
      oServer:DeleteDatabase( ALLTRIM(cDatabase) )
      oServer:CreateDatabase( ALLTRIM(cDatabase) )
   ENDIF

   oServer:SelectDB( ALLTRIM(cDatabase) )
CATCH
   MsgInfo("
Sorry. Your MySql Database '"+ALLTRIM(cDatabase)+"' could no be created.")
   RETURN .F.
END

* MySql Table Creation
TRY
  IF oServer:TableExist(cTable) >0
     IF oServer:DeleteTable(cTable)
        oServer:CreateTable(cTable, aFields)
     ENDIF
  ELSE
     oServer:CreateTable(cTable, aFields)
  ENDIF
CATCH
   MsgInfo("
Sorry. Your MySql Table '"+ALLTRIM(cTable)+"' could no be created.")
   RETURN .F.
END

cTextFile := UPPER(cApp_Path+"
cTable")+".TXT"

COPY TO (cTextFile) DELIMITED WITH TAB
 
IF FILE(cTextFile)
   cTextFile := STRTRAN(cTextFile,"
\","/")   // Change the slashes to enable MYSQL to understand the path
   cQuery := UPPER("
LOAD DATA LOCAL INFILE '"+cTextFile+"' INTO TABLE "+cTable+ " FIELDS TERMINATED BY '"+CHR(9)+ "';")
   oServer:Query(cQuery)
   ERASE (cTextFile)
ELSE
   MsgInfo("
Sorry. There was an error in creating intermediatory TAB Delimited Text file."+CRLF;
                "
To Pouplate your MySql Database '"+ALLTRIM(cDatabase)+"'.")
   RETURN .F.
ENDIF

RETURN .T.

*************************************************************************************************
*** FUNCTION MySqlConnect(cServer, cUser, cPassword) to Connect to MySql DB ***
*************************************************************************************************

FUNCTION MySqlConnect(cServer, cUserName, cPassword)

LOCAL lConnected := .F.

oServer := TMySQLServer():New(ALLTRIM(cServer), ALLTRIM(cUserName), ALLTRIM(cPassword))

IF oServer:NetErr()
   MsgInfo(oServer:Error())
ELSE
   lConnected := .T.
ENDIF

RETURN lConnected

****************************
*** EOF() dbf2sql.prg ***
****************************

User avatar
RAMESHBABU
 
Posts: 624
Joined: Fri Oct 21, 2005 5:54 am
Location: Secunderabad (T.S), India


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 86 guests