2011-09-14 15 views
1

私はExcelプロジェクトを使用して家具の価格を計算しています。最初のタスクは、データベースからすべてのマテリアルを選択することです。 これはコードです:アクセスMDBファイルを照会しながら、最近、私はいくつかの問題を思い付いたVBA:サーバー上でExcelを使用したアクセスを照会


Sub Material_search() 
Dim cnt  As New ADODB.connection 
Dim rst  As New ADODB.Recordset 
Dim rcArray As Variant 
Dim sSQL As String 
Dim db_path As String, db_conn As String 
Dim item As String 

item = Replace(TextBox1.Text, " ", "%")  ' Search word 
sSQL = "Select Data, NomNr, Preke, Matas, Kaina, Tiek from VazPirkPrekes " & _ 
     "Where VazPirkPrekes.PirkVazID IN (SELECT VazPirkimo.PirkVazID FROM VazPirkimo Where VazPirkimo.Sandelys like '%ALIAVOS')" & _ 
     " and Year(VazPirkPrekes.Data)>=2011 and Preke Like '%" + item + "%' and Kaina > 0" & _ 
     " Order by Preke, Data Desc" 
db_path = Sheets("TMP").Range("B6").value 
db_conn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & db_path & ";" 
cnt.Open db_conn 
rst.Open sSQL, cnt, adOpenForwardOnly, adLockReadOnly 
ListBox1.Clear 
If Not rst.EOF Then 
    rcArray = (rst.GetRows) 
    rcArray = WorksheetFunction.Transpose(rcArray) 
    Dim a As Variant 
    With ListBox1 
     .ColumnCount = 6 
     .list = rcArray 
     .ListIndex = -1 
    End With 
End If 
rst.Close: Set rst = Nothing 
cnt.Close: Set cnt = Nothing 
Label4.Caption = UBound(ListBox1.list) + 1 
End Sub 

。問題は、データベースファイルがローカルディスク上にある場合、検索は非常に高速ですが、サーバーにデータベースファイルを置くと、検索に10倍の時間がかかりますが、これは受け入れられません。

このコードの最適化はありますか?またはそれは、サーバーの問題クエリがアクセスデータベースエンジンは、両方のテーブルからすべての190K行を取り出す必要があること、事前

+0

コードを最適化した場合であっても - それができる仮定 - - 問題はリモートクエリであることは明らかです。それはネットワークの速度、待ち時間、またはAccessがこのために設計されていないという事実のためでしょうか。アクセスを捨てて目的に合ったものに移動できない場合は、クエリをパラメトリックにしてAccessに格納することができますExcelプロジェクトから遠隔に呼び出すことができます。しかし、私はまだ違いがないと思っています:P – Xophmeister

+1

一般的な問題は長いパスです。マップされたドライブを使用しようとしましたか? – Fionnuala

+1

@Xophmeisterアクセス​​はサーバー上で正常に動作し、何年も行っています。これのために設計されています。バックエンドがサーバー上で、フロントエンドがユーザーのPC上にあるマルチユーザー環境に推奨されるMicrosoftの記事をご覧ください。 – Fionnuala

答えて

1

おかげです。遅いことは驚くことではないが、dbエンジンがネットワーク上で2 * 190Kの行を取得しなければならない場合、遅さが複合化される。

TextBox1.Textは「foo」を含んでいる場合、これはあなたが実行するDBエンジンを求めている文です:

Select Data, NomNr, Preke, Matas, Kaina, Tiek 
from VazPirkPrekes 
Where 
    VazPirkPrekes.PirkVazID IN (
     SELECT VazPirkimo.PirkVazID 
     FROM VazPirkimo 
     Where VazPirkimo.Sandelys like '%ALIAVOS') 
    and Year(VazPirkPrekes.Data)>=2011 
    and Preke Like '%foo%' 
    and Kaina > 0 
Order by Preke, Data Desc 

それがどのかを決定する前に、エンジンがVazPirkimoテーブルからすべての190Kの行を取得する必要がありますその中には "ALIAVOS"で終わるSandelys値が含まれています。選択基準がの値が "ALIAVOS"で始まる値の場合、エンジンはSandelysのインデックスを使用して、VazPirkimoから取得する必要がある行の数を制限できます。ただし、そのアプローチはおそらくオプションではないため、VazPirkimoに数値フィールドSandelys_groupを追加し、Sandelys_groupにインデックスを作成することを検討してください。サンデリーが終わるところのすべての行に、 "ALIAVOS"と同じSandelys_group番号(1)を与えます。次に、あなたの「IN()」の条件は、これを次のようになります。

SELECT VazPirkimo.PirkVazID 
FROM VazPirkimo 
Where VazPirkimo.Sandelys_group = 1 

Sandelys_groupのインデックスは、DBエンジンがうまくいけば、テーブル内190K行の小さなサブセットになるだけ一致する行を取得することができます。

クエリを高速化するために他にも変更が加えられています。それは、データのインデックスでは、2011年からあるそれらのどれかを決定する前に、これははるかに高速である必要があり

Year(VazPirkPrekes.Data)>=2011 

VazPirkPrekesからすべての190Kの行を取得するために、DBエンジンを強制的に:あなたの句からこの基準を見てください:

基準が速くカイナのインデックスとなります
VazPirkPrekes.Data >= #2011-01-01# AND VazPirkPrekes.Data < #2012-01-01# 

この:Prekeとデータのインデックスのための頼むBY

Kaina > 0 

ご注文。

Order by Preke, Data Desc 

どれかそれらの変更のすべては、私がどのくらいで知らないけれども、クエリのスピードアップに役立つ可能性があります。この殺人者の基準は次のとおりです。

Preke Like '%foo%' 

ここでの問題は、 "Sandelys like like"の問題と同様です。これは、Prekeが "foo"で始めるのではなく "foo"を含む行を要求するため、dbエンジンはPrekeのインデックスを利用して一致する行のみを取得することはできません。 190KのVazPirkPrekes行をすべて検索して一致するものを見つけなければなりません。このために別の基準を使用できる場合を除き、クエリの処理速度をどの程度向上できるかは限定されます。

+1

元のWHERE句は1つのsargable基準を持つので、 'Kaina'フィールドがインデックスされていると仮定すると、テーブル全体をプルしません。しかし、あなたの他のすべての観察結果が目立ちます。 –

0

おかげさまで、ありがとうございましたが、問題は、サーバーにデータベースファイルを置いた場合にのみ発生すると言いました。そして、最適化の助けがそれほどありません。しかし、私は他の考えを考えました。

空の空白を検索すると、約40kのレコードが返されます(これらのレコードは必要なものすべてをカバーします)。ですから、これらのレコードをすべてworkbook_activateイベントの個別のシートに置き、後でそのシートでのみクエリを実行します。

Sub Database_upload() 
    Application.DisplayAlerts = False 
    On Error Resume Next 
    Sheets("DATA_BASE").Delete 
    On Error GoTo 0 
    Application.DisplayAlerts = False 
    Sheets.Add 
    ActiveSheet.name = "DATA_BASE" 
    Sheets("DATA_BASE").Visible = False: Sheets("DARBALAUKIS").activate 
    Dim cnt  As New ADODB.connection 
    Dim rcArray As Variant 
    Dim sSQL As String 
    Dim db_path As String, db_conn As String 
    Dim item As String 
    Dim qQt As QueryTable 
    item = "" 'search for empty blanks 
    sSQL = "Select Data, NomNr, Preke, Matas, Kaina, Tiek from VazPirkPrekes " & _ 
     "Where VazPirkPrekes.PirkVazID IN (SELECT VazPirkimo.PirkVazID FROM VazPirkimo Where VazPirkimo.Sandelys like '%ALIAVOS')" & _ 
     " and Year(VazPirkPrekes.Data)>=2011 and Preke Like '%" + item + "%' and Kaina > 0" & _ 
     " Order by Preke, Data Desc" 

    db_path = Sheets("TMP").Range("B6").value 
    db_conn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & db_path & ";" 

    db_conn = "ODBC;DSN=MS Access 97 Database;" 
    db_conn = db_conn & "DBQ=" & db_path 
    Set qQt = Sheets("Sheet1").QueryTables.Add(connection:=db_conn, Destination:=Sheets("Sheet1").Range("A1"), Sql:=sSQL) 
    qQt.Refresh BackgroundQuery:=False 
End Sub 

結果:

プログラムが起動時に時間がかかりますが、検索時間が許容可能である - 私のための問題が解決さ:)