2011-07-12 10 views
1

これは、問題を説明するための一時的なテーブルで作成されたテストシナリオです。最初のインデックスを使用することができませんでし選択されるのはなぜ テーブル@userdataは、ユーザーID とテーブル@users上のインデックスは、IDインデックスを使用していないTSQL

にインデックスを持っているふりを、私はそれが2つの副選択よりも1つの副選択でより良い実行することになり仮定しましたか?

バージョン - のMicrosoft SQL Server 2008 R2の(RTM) 互換性レベル - SQL Serverの2000

-- test tables 
DECLARE @userdata TABLE(info VARCHAR(50), userid INT) 
DECLARE @users TABLE(id INT, username VARCHAR(20), superuser BIT) 

-- test data 
INSERT @users VALUES(1, 'superuser', 1) 
INSERT @users VALUES(2, 'testuser1', 0) 
INSERT @users VALUES(3, 'testuser2', 0) 
INSERT @userdata VALUES('secret information', 1) 
INSERT @userdata VALUES('testuser1''s data', 2) 
INSERT @userdata VALUES('testuser2''s data', 3) 
INSERT @userdata VALUES('testuser2''s data',3) 

DECLARE @username VARCHAR(50) 
SET @username = 'superuser' 
--SET @username = 'testuser1' 


--The superuser can read all data 
--The testusers can only read own data 

-- This sql can't use indexes and is very slow 
SELECT * 
FROM @userdata d 
WHERE EXISTS 
(SELECT 1 FROM @users u 
WHERE u.username = @username AND u.superuser = 1 OR 
u.id = d.userid AND u.username = @username) 

-- This sql uses indexes and performs well 
SELECT * 
FROM @userdata d 
WHERE EXISTS 
(SELECT 1 FROM @users u 
WHERE u.username = @username AND u.superuser = 1) 
OR EXISTS (SELECT 1 FROM @users u 
WHERE u.ID = d.userid 
AND u.username = @username) 
+1

使用しているSQL Serverのバージョンは? –

+0

私の質問にバージョンが含まれています –

+0

テーブル(およびユーザーあたりの行)に含まれる行の数はどのくらいですか?SELECT * FROM @userdata d WHERE EXISTS(SELECT * FROM @users u WHERE u.username = @username AND (u.superuser = 1 OR u.id = d.userid)) 'は他の2つのクエリに対して相対的に実行されますか? –

答えて

1

私は、orは、クエリアナライザが問題のあるクエリプランを思いつくためにいくつかの問題を引き起こすと思います。 これはあなたの質問に対する答えではなく、このクエリを実行する別の方法です。インデックス以外にも、@ users.usernameのインデックスを提案しています。

if exists(select * from @users where username = @username and superuser = 1) 
begin 
    select * 
    from @userdata 
end 
else 
begin 
    select d.* 
    from @userdata as d 
    inner join @users as u 
     on d.userid = u.id 
    where u.username = @username 
end 
+0

最後のsqlの所要時間は1秒未満です。最初のsqlの所要時間は約5秒です。だから、ユーザーネームにインデックスを追加するのは、少なくともまだではありません。私がプログラム/データベースを販売した会社は、私が少しでも変更を加えれば、すべてのサポートを取り消すでしょう。 –

0

その可能性の問題ははそれができないと、インデックスを使用していない文句を言わないSQL であること。彼らはこれのための様々な理由です。

force it to use an indexを試すことができます。そのようにクエリが遅くなることがあります。

ALTER INDEX ixFoo REBUILDを試してインデックスを再構築できます。インデックスが過度に断片化されているため、インデックスが使用されない可能性があります。

UPDATE STATISTICSでもお試しいただけます。

+0

私はインデックスが問題だとは思わない。私が言及したように、私が "存在"を分割すると、SQLはインデックスをうまく使用します。 –

1

ローカル変数(あなたの場合は@ユーザー名)を使用すると、SQL Serverは常に最適なプランを作成するとは限りません。

ローカル変数が使用されているため、SQL Serverがインデックスを使用しない例については、次のリンクを参照してください。http://www.sqlbadpractices.com/using-local-variables-in-t-sql-queries/

関連する問題