Sql-Server

由於不同的排序規則而沒有使用索引 - 有什麼解決方法嗎?

  • September 3, 2018

我正在執行以下查詢:

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

當我查看查詢執行計劃時,我看到了:

在此處輸入圖像描述

OBS。使用的索引(表 tbl_country 和 tbl_country2)是相同的,只是我錯誤地輸入了錯誤的名稱。

我的數據庫中有不同的排序規則。 在此處輸入圖像描述

CABrochure.dbo.tbl_country表和第二個表之間的唯一區別CRMReferences.dbo.tbl_country2collation.

第一個表是同義詞,但這不會改變任何東西。 在此處輸入圖像描述

我已經創建(並填充了所有數據)與表CRMReferences.dbo.tbl_country2相同,我已經為列中使用的列使用了兼容的排序規則,如下所示。tbl_country``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 此表位於一個名為的數據庫中cola,其排序規則為Latin1_General_CI_AS

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不同排序規則的列來做這些關節並且仍然使用索引?

關鍵問題是基於排序規則的行順序,尤其是當VARCHAR列使用 SQL Server 排序規則時。使用COLLATE關鍵字更改執行時排序規則不會更改索引中行的物理順序。唯一的修復是:

  1. 更改CHAR/VARCHAR列的排序規則以使用 Windows 排序規則。(這是最好的選擇)
  2. 用於COLLATE強制排序規則為 SQL Server(即以 開頭SQL_)排序規則。

在使用上面Solomon Rutzky回答的建議編號2後,我將原始查詢更改為轉換為COLLATE,如下所示:SQL_%

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

我得到了這個更好的執行計劃,它可以進行索引搜尋 ,如下圖所示:

在此處輸入圖像描述

引用自:https://dba.stackexchange.com/questions/216432