比較兩個表中的字元串 SQL Server 2014
我在 SQL Server 2014 數據庫中使用這兩個表:
CREATE TABLE #FORMULAS ( [ID] [int] IDENTITY(1,1) NOT NULL, [DataSourceAddress] [nvarchar](255) NULL, [Description] [nvarchar](255) NULL ) CREATE INDEX [IX_FORMULAS] ON #FORMULAS ([DataSourceAddress] ASC) CREATE TABLE #PARAMETERS ( [ID] [int] IDENTITY(1,1) NOT NULL, [Datetime] DateTime NULL, [ParameterName] [nvarchar](255) NULL, [Value] float NULL ) CREATE INDEX [IX_PARAMETERS] ON #PARAMETERS([ParameterName] ASC) INSERT INTO #FORMULAS ([DataSourceAddress], [Description]) VALUES ('(parameter1+parameter2+parameter3)/3', 'Formula description 1'), ('parameter4', 'Formula description 2'), ('(parameter5*1000)', 'Formula description 3'); INSERT INTO #PARAMETERS ([Datetime], [ParameterName], [Value]) VALUES ('2016-01-26 11:40:00.000', 'parameter1', 1), ('2016-01-26 11:40:00.000', 'parameter2', 2), ('2016-01-26 11:40:00.000', 'parameter3', 3), ('2016-01-26 11:40:00.000', 'parameter4', 4), ('2016-01-26 11:40:00.000', 'parameter5', 5), ('2016-01-26 11:40:00.000', 'parameter6', 6), ('2016-01-26 11:44:00.000', 'parameter1', 1), ('2016-01-26 11:44:00.000', 'parameter2', 2), ('2016-01-26 11:44:00.000', 'parameter3', 3), ('2016-01-26 11:44:00.000', 'parameter4', 4), ('2016-01-26 11:44:00.000', 'parameter5', 5), ('2016-01-26 11:44:00.000', 'parameter6', 6);
我想選擇與表格
#FORMULAS
的列匹配[ParameterName]
的表格參數#PARAMETERS
。例如,取表的值 ‘(parameter1+parameter2+parameter3)/3’並接收包含
#FORMULAS
的表的所有行。#PARAMETERS``'parameter1','parameter2','parameter3'
我正在使用以下選擇:
SELECT A.[Datetime], A.[ParameterName], B.[Description], A.[Value] FROM #PARAMETERS A JOIN #FORMULAS B ON CHARINDEX(A.[ParameterName], B.[DataSourceAddress]) > 0
該
#PARAMETERS
表有超過 160000 行(有 1174 個唯一的ParameterNames
),#FORMULAS
有 3283 行。查詢需要很長時間才能完成,超過 10 分鐘。有沒有更快的查詢方法?
具有良好性能的萬用字元匹配字元串總是很棘手,但這是一個盡力而為的嘗試。
首先,您的索引可以改進。#PARAMETERS 上的索引僅包含實際
ParameterName
列,如果您需要參數列表,這很好,但是當您需要任何其他列時,索引對 SQL Server 將無用,它會恢復為掃描整個表. 我建議通過將索引更改為聚集索引來解決此問題:CREATE UNIQUE CLUSTERED INDEX [IX_PARAMETERS] ON #PARAMETERS (ParameterName, [Datetime]) WITH (DROP_EXISTING=ON); -- Remove this row if the index doesn't already exist.
聚集索引包括表中的每一列,這會自動使聚集索引成為覆蓋索引。
從這裡,我更新了您的查詢以執行三件事:
- 收集#PARAMETERS 中的每個唯一參數。
- 對於每個唯一參數,在#FORMULAS 中查找匹配的公式。這是昂貴的部分,並且沒有索引會真正改善這種搜尋,因為搜尋條件 (LIKE) 不是sargable。這意味著,無論是否有索引,SQL Server 都會針對每個參數遍歷表中的每一行(所謂的掃描)。
- 最後,加入#PARAMETERS 以獲取所有日期和值。這是一種相對便宜和有效的操作。這就是#PARAMETERS 上修改後的索引有幫助的地方。
這是結果查詢:
SELECT A.[Datetime], p.[ParameterName], B.[Description], A.[Value] FROM (SELECT DISTINCT ParameterName FROM #PARAMETERS) p CROSS APPLY ( SELECT * FROM #FORMULAS B WITH (FORCESCAN) WHERE B.DataSourceAddress LIKE N'%'+p.ParameterName+N'%') AS B INNER JOIN #PARAMETERS AS A ON p.ParameterName=A.ParameterName;
我添加
WITH (FORCESCAN)
以消除關鍵查找。您可以嘗試使用或不使用此提示的查詢。如果我有更多的時間來處理這個問題並且這是一個超級關鍵的查詢,我可能會 (a) 重塑表和/或 (b) 考慮將 #FORMULAS 中的數據作為 XML 數據儲存並添加 XML 索引,這將消除 LIKE 匹配。
腳註:即使您只是在搜尋“parameter1”,像您在此處所做的文本匹配(
LIKE
並且CHARINDEX
在此處幾乎相同)將包括帶有參數“parameter10”和“parameter11”的公式。