VFP與SQL Server的連結與最佳化

內容:

建置測試環境

  1. 請先利用 sql server enterprise manager去建立一個 database,叫做demo,然後利用 Query Analyzer 執行以下的sql script
    [sql]use demo
    if exists (select * from sysobjects where id = object_id(N'[dbo].[demo]’) and OBJECTPROPERTY(id, N’IsUserTable’) = 1)
    drop table [dbo].[demo]
    GO
    CREATE TABLE dbo.[demo] (
    cus_no int IDENTITY (1, 1) NOT NULL ,
    cus_name char (10) NOT NULL ,
    comment text NULL
    ) ON PRIMARY TEXTIMAGE_ON PRIMARY
    GOALTER TABLE dbo.demo WITH NOCHECK ADD
    CONSTRAINT PK_demo PRIMARY KEY NONCLUSTERED
    (
    cus_no
    ) ON PRIMARY
    GO
    [/sql]
  2. 請再設定一下控制台中的ODBC
  3. 設定一下 class 裡面的 demo.vcx 中的 prjhook QueryRunFile Event 中的路徑,然後在專案上面點一下滑鼠右鍵,選擇 專案資訊,接著把專案類別設為 demo.vcx,然後以後你執行程式的時候,就只要按 執行 就好了
  4. 接著去變更一下 database 中的 connection

測試

以程式動態模擬 1000 筆資料寫入 sql server 資料庫中,直接利用 vfp 的 connection + remote view
硬體: cyrix 200 + 128 mb ram + 4g hd
軟體: m$ sql server 7 + ado 2.6

情況 1 :
不設 buffering,vfp 當然是每新增一筆, 就會寫一筆到 sql server 中,想當然耳,速度超慢

情況 2 :
設定 buffering 為 5,這個時候,新增就粉快了,因為新增的資料都是放到 local 端,不過 tableupdate 的時候,就超慢了

情況 3 :
設定 buffering 為 5, batchupdatecount 為 1000, prepared 為 true
第一次新增 1000 筆,tableupdate 寫入,僅僅花了二分鐘多左右,效率還算讓人滿意
在程式執行的同時,我也有利用 sql 的 profiler 去觀察,vfp的確有先產生 prepare 的指令, 再執行 insert 的動作,仔細看了一下 tableupdate 的指令說明
tableupdate 的第一個參數如果帶 1, 而且 buffering 有開啟的時候,就會只把有變動的記錄更新回去
這一點我呆會會再另外用另外一種方法來測試是否真的有這麼去tableupdate
第二次執行的時候,花了約四分鐘,這次我發現vfp有多花一些時間在requery()上,所以我把 use demo 改為 use demo nodata
果然就又回復到約二分鐘多左右了,這次我把 prepare 拿掉試試看,發現了很有趣的現象,profiler 中,仍然使用了 prepare,不知道是不是因為 odbc driver 的關係

第四次(prog2)
測試 requery() 的速度
我知道memo的大小會影響速度,所以直接先把 fetchmemo 設為 false,程式很快就run完了,我感到質疑,因此我用browse去看
我發現 vfp 會 requery() 一個程度之後,開始在background去抓資料
如果這個時候去browse,速度就變的粉慢,怎麼變快??
於是我接著把 FetchAsNeeded 設為 True, FetchSize 設為 100
重新執行, 果然速度變快很多,因為vfp只抓了 100 筆
我利用 browse 去觀察的時候,向下 page down, vfp 還會自動往下抓100筆記錄
這真是太棒了
不過我後來直接把 scroll bar 移到最下面,這個requery的時間就很久了

第五次(form1)
我寫了一個簡單的表單,寫的過程,遇到一個小問題,我在dataenvironment中拉入view,接著把view拖到表單上,產生grid的時候粉慢,這時候我建議各位先在指令列下 use demo nodata, 然後再來拖,會順利很多!!
做好的畫面如form1,畫面很簡單,右上角是我測試的重點之一,我輸入一個數值,按下”跳到”,會自動移到該筆記錄去
當我 go 100 的時候,果然vfp會自動抓下一百筆資料
另外當我點選到 memo 欄位時,vfp也會自動去抓取該欄位的memo值
(因為之前把fetchmemo設為false,所以不會抓memo值)
不過這時候又產生了另外一個問題
如果我想知道總共有多少記錄的時候要怎麼辦呢??雖然輔助說明中說requery()之後,
會把取得的記錄數目存放在_tally變數中,but似乎不是這樣,因為我取得的_tally總是與事實不符
翻遍輔助說明,看來都沒有適合的指令可以取得
只好利用 select count() 了
我把這段指令寫在 “總筆數!!” 這個按鈕上
千萬不要用 reccount() ,這會把所有資料下載下來!!

FetchAsNeeded??

第六次 (form1)
這次我們要試的是 tableupdate 是否真的只把我們有更動的資料寫回去
因此我們使用 tableupdate( 1, .T. ) 來作
可是粉奇怪,profiler 並沒有顯示任何 update 的動作
這太奇怪了~~
我搞了好久
才在 vfp 的 programmer’s guide 找到
當 fetchasneeded 設為 true 的時候,是無法做任何更新動作的!!!!
必須要先 sqlcancel 之後才能去做
最後實驗 tableupdate( 1, .T. )也順利成功
程式碼在[奇數碼更新]裡面!!
vfp 果然會只更新有變動的部分而已!!!

SELECT-SQL UNION ALL Clause

很久以前就知道在別的大型資料庫系統裡, Select 有 Union這個子句(clause)
但我不知道VFP有這個子句
前兩天在看VFP輔助說明的時候,才發現到,VFP也有。
那那那…這個指令有啥好處呢?
我用個範例來做說明好了,這個範例是從BBS的Database版上借下來的,有經過改寫,原本是ORACLE的範例:
首先先建立一個Database,然後建好多個 Table,其結構都相同
CREATE DATABASE DEMO
CREATE TABLE DEMO_1995 ;
(TRANS_DATE D, cTEXT C(80), ;
CHECK (TRANS_DATE>={^1995/01/01} AND TRANS_DATE={^1996/01/01} AND TRANS_DATE={^1997/01/01} AND TRANS_DATE={^1998/01/01} AND TRANS_DATE={^1999/01/01} AND TRANS_DATE={^1998/01/01} AND TRANS_DATE<{^1999/07/01}
或者 你也可以不需要建DEMO這個View
你也可以直接用
SELECT * FROM DEMO_1995 ;
UNION ALL ;
SELECT * FROM DEMO_1996 ;
UNION ALL ;
SELECT * FROM DEMO_1997 ;
UNION ALL ;
SELECT * FROM DEMO_1998 ;
UNION ALL ;
SELECT * FROM DEMO_1999
這個時候 也許你會問,這有啥好處呢?? 看來是沒有啊 請注意…
相信各位都曾經有過這種迷惘-以年度區分(或其他)的資料檔到底是要分開呢?還是要放在一起?
假設你選擇了分開,那麼在作整合查詢的時候,就會相當的麻煩。
通常只能先建立一個暫存資料檔,然後依序將零星的資料匯入之後,再對此一暫存資料檔作查詢。
使用了union all,就可以不需要那麼麻煩了。