web-dev-qa-db-ja.com

照合順序が異なるためインデックスが使用されていません-回避策はありますか?

次のクエリを実行しています。

SET ROWCOUNT 50

SELECT UL.*
                FROM COLA.dbo.tbl_UserLogin ul    
          INNER JOIN CABrochure.dbo.tbl_country co
                  ON ul.CountryCode      COLLATE DATABASE_DEFAULT = 
                     co.cola_countrycode COLLATE DATABASE_DEFAULT  

SELECT UL.*
                FROM COLA.dbo.tbl_UserLogin ul    
          INNER JOIN CRMReferences.dbo.tbl_country2 co
                  ON ul.CountryCode    = co.cola_countrycode 

SET ROWCOUNT 0

クエリ実行プラン を見ると、これがわかります:

enter image description here

OBS。使用されているインデックス(テーブルtbl_countryとtbl_country2)は同じですが、誤って名前を付けました。

データベースに異なる照合順序があります。 enter image description here

CABrochure.dbo.tbl_countryテーブルと2番目のテーブルCRMReferences.dbo.tbl_country2の唯一の違いは、collationです。

最初の表は同義語ですが、何も変更されません。 enter image description here

CRMReferences.dbo.tbl_country2テーブルと同じtbl_countryを作成(およびすべてのデータを入力)しました[〜#〜] but [〜#〜]以下のように、cola_countrycodeで使用されるinner join列に互換性のある照合を使用しました。

IF OBJECT_ID('[dbo].[tbl_country2]') IS NOT NULL 
DROP TABLE [dbo].[tbl_country2] 
GO
CREATE TABLE [dbo].[tbl_country2] ( 
[co_code]           VARCHAR(2)                       NOT NULL,
[country_id]        INT                              NOT NULL,
[co_name]           VARCHAR(50)                      NOT NULL,
[co_recruiting]     BIT                                  NULL,
[co_rank]           INT                                  NULL,
[co_display]        CHAR(10)                             NULL,
[CRM_GuidId]        VARCHAR(100)                         NULL,
[cola_countrycode]  CHAR(2) COLLATE Latin1_General_CI_AS NULL)

ALTER TABLE [dbo].[tbl_country2] ADD  CONSTRAINT [PK_TBL_COUNTRY2] 
PRIMARY KEY CLUSTERED (  [co_code] ASC  )  

CREATE NONCLUSTERED INDEX I_cola_countrycode  
ON [dbo].[tbl_country2] (  [cola_countrycode] ASC  )  

このクエリのメインテーブル:dbo.tbl_UserLoginこのテーブルは、照合がLatin1_General_CI_ASであるcolaというデータベースにあります。

USE [cola]
go
exec sp_gettabledef 'dbo.tbl_UserLogin'


IF OBJECT_ID('[dbo].[tbl_UserLogin]') IS NOT NULL 
DROP TABLE [dbo].[tbl_UserLogin] 
GO
CREATE TABLE [dbo].[tbl_UserLogin] ( 
[UserID]         NUMERIC(18,0)    IDENTITY(1,1) NOT NULL,
[UserName]       VARCHAR(50)      NULL,
[Email]          VARCHAR(255)     NULL,
[FirstName]      VARCHAR(50)      NOT NULL,
[middleName]     VARCHAR(50)      NULL,
[LastName]       VARCHAR(50)      NOT NULL,
[CountryCode]    VARCHAR(2)       NULL,
[Gender]         CHAR(1)          NULL,
[PasswordSalt]   INT              NULL,
[ApplicantID]    NUMERIC(18,0)    NULL,
[InterviewerID]  NUMERIC(18,0)    NULL,
[Password]       VARCHAR(50)      NULL,
[DateOfBirth]    DATETIME         NULL,
[ReligionDenom]  VARCHAR(30)      NULL,
[createdOn]      DATETIME         NOT NULL  
 CONSTRAINT [DF_tbl_UserLogin_createdOn] 
 DEFAULT (getdate()),
[RegionId]       NUMERIC(18,0) NULL,
[faceTimeId]     VARCHAR(50) NULL  
CONSTRAINT [DF__tbl_UserL__faceT__7E1394B9] DEFAULT (NULL),
CONSTRAINT   [PK_tbl_UserLogin]  PRIMARY KEY CLUSTERED    
             ([UserID] asc),
CONSTRAINT   [uc_Email]  UNIQUE NONCLUSTERED ([Email] asc) 
   WITH FILLFACTOR = 100,
    CONSTRAINT   [ck_uniqueApplicantID]        
         CHECK ([dbo].[validateApplicantIDExistance]([applicantID])<=(1)),
    CONSTRAINT   [ck_uniqueInterviewerID]      
        CHECK ([dbo].[validateInterviewerIDExistance]([InterviewerID])<=(1)))

    GO

CREATE NONCLUSTERED INDEX [idx_firstname] 
   ON [dbo].[tbl_UserLogin] ([FirstName] asc)
   INCLUDE ([ApplicantID], [CountryCode], [Email], [LastName])
   WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX [idx_interviewerID] 
   ON [dbo].[tbl_UserLogin] ([InterviewerID] asc)
   WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX [idx_lastname] 
   ON [dbo].[tbl_UserLogin] ([LastName] asc)
   INCLUDE ([ApplicantID], [CountryCode], [Email], [FirstName])
   WITH FILLFACTOR = 100
CREATE NONCLUSTERED INDEX [IX_tbl_UserLogin_ApplicantID] 
   ON [dbo].[tbl_UserLogin] ([ApplicantID] asc)
   INCLUDE ([UserID])
   WITH FILLFACTOR = 100

この環境のさまざまなデータベースのさまざまな照合順序が特定の目的に役立つかどうかはわかりません。それらをすべて同じにできるかどうかはわかりません。データベースの照合順序を変更するプロセスを経由しないようにしています。

それ以外、

異なる照合順序のchar or varchar列に基づいてこれらのジョイントを実行しても、インデックスを使用できる方法はありますか?

3

重要な問題は、特にVARCHAR列がSQL Server照合順序を使用している場合に、照合順序に基づく行の順序です。 COLLATEキーワードを使用して実行時の照合順序を変更しても、インデックス内の行の物理的な順序は変更されません。唯一の修正は次のとおりです。

  1. CHAR/VARCHAR列の照合順序を変更して、Windows照合順序を使用します。 (これが最良の選択肢です)
  2. COLLATEを使用して、照合順序を強制的にSQL Server(つまり、SQL_で始まる)照合順序にします。
3
Solomon Rutzky

Solomon Rutzky 'の提案番号2を使用した後、元のクエリを次のようにSQL_% COLLATEに変換するように変更しました。

SET ROWCOUNT 50

SELECT UL.*
                FROM COLA.dbo.tbl_UserLogin ul    
          INNER JOIN CABrochure.dbo.tbl_country co
                  ON ul.CountryCode        
                     COLLATE SQL_Latin1_General_CP1_CI_AS    
                  = co.cola_countrycode 
                    COLLATE SQL_Latin1_General_CP1_CI_AS 


SELECT UL.*
                FROM COLA.dbo.tbl_UserLogin ul    
          INNER JOIN CRMReferences.dbo.tbl_country2 co
                  ON ul.CountryCode    = co.cola_countrycode 

SET ROWCOUNT 0

私はこれを手に入れました インデックスシークを実行するはるかに優れた実行プラン 下の図でわかるように:

enter image description here

1