2012-03-01 17 views
0

データベースでクエリを最適化しようとしています。そのクエリは、次のようになります。Sql Join on User Defined関数:最適化する方法

select * from Account 
    inner join udf_Account('user') udfAccount 
    on Account.Id = udfAccount.AccountId 

実は本当のクエリがはるかに長いですが、最も重要な点は、それが、内側には、ユーザIDに依存して、ユーザー定義関数(UDF)に参加し、いくつかが含まれていることです。 (これは、クエリ評価中に変化しない定数パラメータです)。

大量のデータのため、私のクエリは、本番データベースでは許容されない約20秒かかります。

私はすでに、一時テーブルに関数の結果を格納し、これらのテーブルをクエリに使用することで、クエリの期間が大幅に短縮されることを確認しました。

私は、次の質問をしています:

  1. 私は一時テーブルを避けることができます。関数には一度しか評価できないことをSQLに伝える方法ではありませんか?一時テーブルを使用すると、私のコードにいくつかの重要な変更があることを暗示しています。これは、別の解決策があれば、うれしいでしょう。

  2. クエリを最適化する他の方法はありますか?

+0

私の機能はすべて「インラインテーブル値」機能であると付け加えておきます。 – Thierry

+0

私はMS SQL Server 2008を使用しています – Thierry

答えて

1

mysqlが "確定的な"関数を呼び出すことを定義したいと思うと思います。あなたのSQLの風味に応じて、これは異なる構文を持つでしょう。しかし、最終的に最大の最適化は、関数をまったく使用しないことですが、ユーザーテーブルにアカウント列を追加するだけです。

+0

申し訳ありませんが、私はMS SQL Server 2008を使用していることを追加することを忘れていました。その機能はユーザー、特に彼/彼女の権利/役割に依存します。クエリが完了するたびに私が知る限り、その関数を再計算する必要があります。 – Thierry

4

SQL Serverでは、機能がMulti-StatementではなくInlineである場合、SQL Serverはtham(マクロに似たもの)をクエリに反映させます。メインクエリでサブクエリと同じように機能します。

これは、概念上、オプティマイザが「より良い」実行計画を立てることを可能にします。

たとえば、参加しているフィールドがソーステーブルから直接派生している場合は、これらのフィールドのインデックスを使用できるようにする必要があります。

クエリ全体と個々の機能を見ることなく、あなたの構文に関してはすでに良い場所にいるようです。次に見たいのは、存在するインデックスであり、テーブルスキャンやインデックススキャンではなく、インデックスシークを目指しています。

(それはすべてのビットに単純だが、それは巨大なトピックであるクエリの最適化のための良いスタートです。)


別のオプションは、あなたのインラインテーブル値関数でCROSS APPLYを使用して見ることです。
(SQL Serverの2005年以降で利用可能)

これは、クエリ内のテーブルからの値は、あなたの関数へのパラメータとして使用することができます。ここでも、関数がインラインであれば、SQL Serverは実行計画を作成するときに関数をインライン展開します。

例は可能です...

SELECT 
    Account.AccountID, 
    subAccount.AccountID  AS SubAccountID, 
    Balance.currentAvailable AS SubAccountBalance 
FROM 
    Account 
CROSS APPLY 
    dbo.getSubAccounts('User', Account.AccountID) AS SubAccount 
CROSS APPLY 
    dbo.getCurrentBalance(SubAccount.AccountID) AS Balance 
WHERE 
    Account.AccountID = 1234