SSMS - 如何在對象資源管理器中進行不區分大小寫的搜尋
**前言:**我不是 指查詢。
SSMS 中有許多地方允許過濾,例如對象資源管理器和探查器,但這些都將過濾器視為區分大小寫,否則沒有可見選項,因此如果您搜尋
contains 'ASDF'
“ASDF_MyEntity”之類的值,但“asdf_MyEntity” “被省略。例如,我們在大型伺服器上有很多SQL 代理作業,我嘗試使用對象資源管理器按項目名稱過濾它們,我們總是在作業名稱前加上前綴。但是,這些顯示為大寫和小寫變體。
另一個案例是在數千個條目中搜尋與模組相關的儲存過程。如果一個名稱不一致(例如 PascalCase 與 camelCase),過濾後的搜尋將忽略它。這似乎是調試幻象的不必要的危險。
此外,對於每種類型的實體(例如表名、儲存過程、作業名等),對象資源管理器中的排序將大寫變體放在小寫之前(所以大寫
Z
在小寫之前a
),所以我要麼必須滾動很多,或檢查兩個不同的過濾器(如果不是全部大寫或全部小寫字母,則檢查更多 - 準確地說是 2 len(name)次)。我意識到我可以手動查詢jobs、tables和其他實體,但鑑於 SSMS 存在,這樣做是荒謬的,因為它的名稱是“SQL Server Management Studio”。
我可以做些什麼來讓 SSMS(和 SQL Server Profiler)像其他所有 Windows 應用程序一樣忽略大小寫?也許我可以在本地更改排序規則設置?
另外,為什麼微軟在實施 SSMS 時會做出這個決定?我發現它只是有害的。
此外,SSMS 的載入初始螢幕顯示“在 Visual Studio 上建構”,它忽略了解決方案資源管理器中的大小寫。
PS 使用 SSMS 2014(版本 12.0.5214.6)。我無法進行任何伺服器端更改,並且我的本地開發環境應與目標伺服器環境匹配以進行測試。
在技術上可以進行這種不區分大小寫的過濾,但這只是由於 SSMS 中的一個錯誤。我沒有 SSMS 2014(版本 12.x),但我確實讓它在 SSMS 17.9.1 和 18.0 Preview 6 中工作,連接到預設排序規則為
Hebrew_100_BIN2
.嘗試一(否)
看到查詢使用
LIKE
,我想我會嘗試使用單字元範圍萬用字元(即[
和]
)。然而,由於某些字元被轉義,傳遞一個模式[Tt][Ee][Ss][Tt]
不起作用。似乎[
,%
和_
都被包裹起來[
並將]
它們變成文字(即不再具有特殊含義)。嘗試 Dos(是)
看到與
LIKE
運算符一起使用的值(即輸入到 UI 中的值)被連接到查詢中,而不是作為變數傳入(即,tbl.name like N''%Test%''
而tbl.name like N''%'' + @_msparam_XX + N''%''
不是用使用者輸入來做這個?嗯,我想知道……“所以我傳入 a'
,它被轉義為''
. 通常這正是單引號應該發生的情況。''
但是,這是在動態 SQL 中使用的,因此它的嵌套比正確轉義的位置更深一層。字元串中的字元串需要將單引號轉義為''''
或雙引號,因為''
僅結束字元串中的字元串。例如,在過濾“表格”時,生成的程式碼(重要的一行)是:
CAST(tbl.is_external AS bit)=@_msparam_5 and tbl.name like N''%Test%'')
如果我通過了“測試”,生成的程式碼將是:
CAST(tbl.is_external AS bit)=@_msparam_5 and tbl.name like N''%Te''st%'')
是的,它確實得到一個“未閉合的引號”錯誤。
我嘗試添加一個
COLLATE
子句,但所有排序規則都有下劃線,所以Latin1_General_100_CI_AS
變成Latin1[_]General[_]100[_]CI[_]AS
. 哦!我們不能傳入
[
或不傳入那些被and%
包裹的東西,但是,我們可以將東西連接到字元串上,例如函式的輸出。而且,我們可以通過將它們作為十六進制/值傳遞來繞過和字元的轉義,然後將它們返回一次。[``]``N'%``[``%``VARBINARY``CONVERT``NVARCHAR
因此,在過濾儲存過程時,我們從正常生成的程式碼開始:
AS bit)=@_msparam_3 and ISNULL(sm.uses_native_compilation,0)=@_msparam_4 and sp.name like N''%Test%'')',N'@_msparam_0 nvarchar(4000),@_msparam_1
為了完成這項工作,我們需要傳入一個具有以下結構的字元串(代替“Test”):
' + CONVERT(NVARCHAR(MAX), 0x.....) AND 'x' <> '
我們可以
--
在末尾使用而不是AND 'x' <> '
,但該AND
構造確保如果在該部分之後有查詢的其他部分並且在同一行上,則它會繼續按預期執行。要生成我們的“轉義”過濾器,我們可以使用以下內容:
SELECT CONVERT(VARBINARY(MAX), N'[Tt][Ee][Ss][Tt]%'); -- must end with "%" -- 0x5B00540074005D005B00450065005D005B00530073005D005B00540074005D002500
將該十六進制值粘貼到我們的 SQL 注入解決方法中,我們得到:
' + CONVERT(NVARCHAR(MAX), 0x5B00540074005D005B00450065005D005B00530073005D005B00540074005D002500) AND 'x' <> '
如果我們將過濾器設置為上面的值,生成的程式碼將是:
AS bit)=@_msparam_3 and ISNULL(sm.uses_native_compilation,0)=@_msparam_4 and sp.name like N''%'' + CONVERT(NVARCHAR(MAX), 0x5B00540074005D005B00450065005D005B00530073005D005B00540074005D002500) AND ''x'' <> ''%'')',N'@_msparam_0 nvarchar(4000),@_msparam_1 nvarchar(4000),@_msparam_2 nvarchar(4000),@_msparam_3 nvarchar(4000),@_msparam_4 nvarchar(4000)',@_msparam_0=N'P',@_msparam_1=N'RF',@_msparam_2=N'PC',@_msparam_3=N'0',@_msparam_4=N'1'
並將生成的程式碼傳遞到
sp_executesql
. 執行的語句在 Profiler 中顯示為:AS bit)=@_msparam_3 and ISNULL(sm.uses_native_compilation,0)=@_msparam_4 and sp.name like N'%' + CONVERT(NVARCHAR(MAX), 0x5B00540074005D005B00450065005D005B00530073005D005B00540074005D002500) AND 'x' <> '%')
這種技術之所以有效,是因為
0xYYYY....
它不是解析器正在尋找的東西。它只是尋找 、 和 的字面值,[
我們並沒有將它們傳遞進去。我們只是傳遞了一些東西,一旦動態 SQL 被執行,它們就會被翻譯成這些值。_``%
但它不需要
VARBINARY
是傳入的字元串。任何傳回字元串的函式都可以工作。您只需要將結尾N'%
與某事連接起來,然後是之前出現的內容%')
,因此:' + {something_ending_with_%'} AND 'x' <> '
. 我本可以用來+ NCHAR(91) + N'Tt' + NCHAR(93) +
表示[Tt]
,但這似乎比連續VARBINARY
文字大得多。但是,如果您只想要一個%
,那麼做+ NCHAR(37) + N'
就可以了。請記住使用NCHAR()
和前綴文字,N
因為這是所有NVARCHAR
數據。嘗試三(非常肯定)
因此,您不希望
[Tt][Ee][Ss][Tt]
每次都創建字元串並將其轉換為VARBINARY
. 我明白了。哦,您無權在 SQL Server 中添加/更改對象。行。但是您確實可以訪問tempdb
,對嗎?如果你可以在 中創建一個函式tempdb
,那麼這會更容易。只需執行以下操作:USE [tempdb]; IF (OBJECT_ID(N'dbo.ObjectFilter') IS NOT NULL) BEGIN DROP FUNCTION dbo.ObjectFilter; END; GO CREATE FUNCTION dbo.ObjectFilter(@Name [sysname], @Filter [sysname]) RETURNS BIT AS BEGIN IF (@Name LIKE N'%' + @Filter + N'%' COLLATE Latin1_General_100_CI_AS_SC) BEGIN RETURN 1; END; RETURN 0; END; GO
然後將過濾器設置為:
' AND tempdb.dbo.ObjectFilter(sp.name, N'Test') = 1 AND 'x' <> '
生成的程式碼將是:
CAST(tbl.is_external AS bit)=@_msparam_5 and tbl.name like N'%' AND tempdb.dbo.ObjectFilter(sp.name, N'Test') = 1 AND 'x' <> '%')
您將不得不調整列別名,因為表使用
tbl.name
而不是sp.name
. 但是現在您可以傳入任何字元串,它將使用不區分大小寫的排序規則進行比較!而且,此功能將一直存在,直到實例重新啟動。因此,您只需要每隔一段時間執行一次上述 T-SQL。
{ 丟下麥克風 … 走下舞台 } 😎
補充筆記:
- 請記住,這種技術之所以有效,是因為 SSMS 中存在錯誤。如果該錯誤得到修復,那麼這種解決方法可能會停止工作。請參閱底部的“更新”部分以獲取指向我送出的關於此問題的錯誤報告的連結,以及我送出的增強建議,要求每個可過濾屬性的“不區分大小寫”複選框。
- 從蘭迪的回答:
除非您找到查詢的儲存位置並更改它,否則…
尋找查詢毫無意義。它們來自構成 SSMS 的 DLL。我認為C:\Program Files (x86)\Microsoft SQL Server\140\Tools\Binn\ManagementStudio\Microsoft.SqlServer.Management.Sdk.Sfc.dll可能是其中之一,但不確定。 3. 從鮑勃對這個問題的評論:
SSMS 不強制區分大小寫,除非伺服器排序規則區分大小寫。
這要看情況。排序規則有兩個級別——實例級別和數據庫級別——重要的一個取決於某人試圖過濾的元數據。實例級排序影響過濾實例級元數據(例如登錄、連結伺服器等)和系統數據庫中的元數據。數據庫級排序規則影響過濾使用者數據庫元數據(例如使用者、表等)。在包含/部分包含的數據庫中,過濾數據庫級元數據將始終使用排序規則:
Latin1_General_100_CI_AS_WS_KS_SC
.這種級別的分離解釋了 Randi 的回答中提到的以下發現:
在 CI 伺服器上的 CS DB 上似乎也不可能:
- 來自 Elaskanator 對這個問題的評論:
目前它設置為區分大小寫的二進制排序規則 (Latin1_General_BIN)。
僅供參考:不幸的是,這是一個非常普遍的誤解,但是不,二進制排序規則不區分大小寫
更新
我已向 Microsoft 送出以下回饋項:
使用分析器擷取應用
Contains
過濾器時執行的查詢,我找到了查詢:exec sp_executesql N'SELECT sp.name AS [Name], SCHEMA_NAME(sp.schema_id) AS [Schema], ''Server[@Name='' + quotename(CAST( serverproperty(N''Servername'') AS sysname),'''''''') + '']'' + ''/Database[@Name='' + quotename(db_name(),'''''''') + '']'' + ''/StoredProcedure[@Name='' + quotename(sp.name,'''''''') + '' and @Schema='' + quotename(SCHEMA_NAME(sp.schema_id),'''''''') + '']'' AS [Urn], sp.create_date AS [CreateDate], ISNULL(ssp.name, N'''') AS [Owner], CAST(CASE WHEN ISNULL(smsp.definition, ssmsp.definition) IS NULL THEN 1 ELSE 0 END AS bit) AS [IsEncrypted], CASE WHEN sp.type = N''P'' THEN 1 WHEN sp.type = N''PC'' THEN 2 ELSE 1 END AS [ImplementationType], ISNULL(sm.uses_native_compilation,0) AS [IsNativelyCompiled] FROM sys.all_objects AS sp LEFT OUTER JOIN sys.database_principals AS ssp ON ssp.principal_id = ISNULL(sp.principal_id, (OBJECTPROPERTY(sp.object_id, ''OwnerId''))) LEFT OUTER JOIN sys.sql_modules AS smsp ON smsp.object_id = sp.object_id LEFT OUTER JOIN sys.system_sql_modules AS ssmsp ON ssmsp.object_id = sp.object_id LEFT OUTER JOIN sys.all_sql_modules AS sm ON sm.object_id = sp.object_id WHERE (sp.type = @_msparam_0 OR sp.type = @_msparam_1 OR sp.type=@_msparam_2)and(CAST( case when sp.is_ms_shipped = 1 then 1 when ( select major_id from sys.extended_properties where major_id = sp.object_id and minor_id = 0 and class = 1 and name = N''microsoft_database_tools_support'') is not null then 1 else 0 end AS bit)=@_msparam_3 and ISNULL(sm.uses_native_compilation,0)=@_msparam_4 and sp.name like N''%Test%'')',N'@_msparam_0 nvarchar(4000),@_msparam_1 nvarchar(4000),@_msparam_2 nvarchar(4000),@_msparam_3 nvarchar(4000),@_msparam_4 nvarchar(4000)',@_msparam_0=N'P',@_msparam_1=N'RF',@_msparam_2=N'PC',@_msparam_3=N'0',@_msparam_4=N'0'
其中包含部分:
and sp.name like N''%Test%''
並給我結果:
Name Schema Urn CreateDate Owner IsEncrypted ImplementationType IsNativelyCompiled TestCs dbo Server[@Name='DESKTOP-602CJ92\ 2019-01-28 20:05:28.220 dbo 0 1 0
正如@BobKlimes 所指出的,這意味著它在 CS 伺服器上是不可能的。
在 CI 伺服器上的 CS DB 上似乎也不可能:
因此,我們遇到了與您在添加的連結中提到的相同的問題。
除非您找到查詢的儲存位置並更改它,否則我認為沒有辦法解決它。
嘗試使用計劃指南添加排序規則提示
下面的查詢確實給了我想要的東西,因為我添加了 COLLATE 提示,所以我嘗試使用整理查詢的查詢計劃 XML 在原始查詢上創建計劃指南。
為我提供所需過濾的查詢
exec sp_executesql N'SELECT sp.name AS [Name], SCHEMA_NAME(sp.schema_id) AS [Schema], ''Server[@Name='' + quotename(CAST( serverproperty(N''Servername'') AS sysname),'''''''') + '']'' + ''/Database[@Name='' + quotename(db_name(),'''''''') + '']'' + ''/StoredProcedure[@Name='' + quotename(sp.name,'''''''') + '' and @Schema='' + quotename(SCHEMA_NAME(sp.schema_id),'''''''') + '']'' AS [Urn], sp.create_date AS [CreateDate], ISNULL(ssp.name, N'''') AS [Owner], CAST(CASE WHEN ISNULL(smsp.definition, ssmsp.definition) IS NULL THEN 1 ELSE 0 END AS bit) AS [IsEncrypted], CASE WHEN sp.type = N''P'' THEN 1 WHEN sp.type = N''PC'' THEN 2 ELSE 1 END AS [ImplementationType], ISNULL(sm.uses_native_compilation,0) AS [IsNativelyCompiled] FROM sys.all_objects AS sp LEFT OUTER JOIN sys.database_principals AS ssp ON ssp.principal_id = ISNULL(sp.principal_id, (OBJECTPROPERTY(sp.object_id, ''OwnerId''))) LEFT OUTER JOIN sys.sql_modules AS smsp ON smsp.object_id = sp.object_id LEFT OUTER JOIN sys.system_sql_modules AS ssmsp ON ssmsp.object_id = sp.object_id LEFT OUTER JOIN sys.all_sql_modules AS sm ON sm.object_id = sp.object_id WHERE (sp.type = @_msparam_0 OR sp.type = @_msparam_1 OR sp.type=@_msparam_2)and(CAST( case when sp.is_ms_shipped = 1 then 1 when ( select major_id from sys.extended_properties where major_id = sp.object_id and minor_id = 0 and class = 1 and name = N''microsoft_database_tools_support'') is not null then 1 else 0 end AS bit)=@_msparam_3 and ISNULL(sm.uses_native_compilation,0)=@_msparam_4 and sp.name like N''%Test%''COLLATE Latin1_General_CI_AS)',N'@_msparam_0 nvarchar(4000),@_msparam_1 nvarchar(4000),@_msparam_2 nvarchar(4000),@_msparam_3 nvarchar(4000),@_msparam_4 nvarchar(4000)',@_msparam_0=N'P',@_msparam_1=N'RF',@_msparam_2=N'PC',@_msparam_3=N'0',@_msparam_4=N'0'
結果:
Name Schema Urn CreateDate Owner IsEncrypted ImplementationType IsNativelyCompiled testCs dbo Server[@Name='DESKTOP-602CJ92\ 2019-01-28 20:05:23.830 dbo 0 1 0 TestCs dbo Server[@Name='DESKTOP-602CJ92\ 2019-01-28 20:05:28.220 dbo 0 1 0
創建計劃指南(XML 由於太大而未顯示)遵循此答案
EXEC sp_create_plan_guide @name = 'Filtering', @stmt = N'SELECT sp.name AS [Name], SCHEMA_NAME(sp.schema_id) AS [Schema], ''Server[@Name='' + quotename(CAST( serverproperty(N''Servername'') AS sysname),'''''''') + '']'' + ''/Database[@Name='' + quotename(db_name(),'''''''') + '']'' + ''/StoredProcedure[@Name='' + quotename(sp.name,'''''''') + '' and @Schema='' + quotename(SCHEMA_NAME(sp.schema_id),'''''''') + '']'' AS [Urn], sp.create_date AS [CreateDate], ISNULL(ssp.name, N'''') AS [Owner], CAST(CASE WHEN ISNULL(smsp.definition, ssmsp.definition) IS NULL THEN 1 ELSE 0 END AS bit) AS [IsEncrypted], CASE WHEN sp.type = N''P'' THEN 1 WHEN sp.type = N''PC'' THEN 2 ELSE 1 END AS [ImplementationType], ISNULL(sm.uses_native_compilation,0) AS [IsNativelyCompiled] FROM sys.all_objects AS sp LEFT OUTER JOIN sys.database_principals AS ssp ON ssp.principal_id = ISNULL(sp.principal_id, (OBJECTPROPERTY(sp.object_id, ''OwnerId''))) LEFT OUTER JOIN sys.sql_modules AS smsp ON smsp.object_id = sp.object_id LEFT OUTER JOIN sys.system_sql_modules AS ssmsp ON ssmsp.object_id = sp.object_id LEFT OUTER JOIN sys.all_sql_modules AS sm ON sm.object_id = sp.object_id WHERE (sp.type = @_msparam_0 OR sp.type = @_msparam_1 OR sp.type=@_msparam_2)and(CAST( case when sp.is_ms_shipped = 1 then 1 when ( select major_id from sys.extended_properties where major_id = sp.object_id and minor_id = 0 and class = 1 and name = N''microsoft_database_tools_support'') is not null then 1 else 0 end AS bit)=@_msparam_3 and ISNULL(sm.uses_native_compilation,0)=@_msparam_4 and sp.name like N''%Test%'')', @type = 'SQL', @params = N'@_msparam_0 nvarchar(4000),@_msparam_1 nvarchar(4000),@_msparam_2 nvarchar(4000),@_msparam_3 nvarchar(4000),@_msparam_4 nvarchar(4000)', @hints = @planXML GO
雖然我可以創建計劃指南,但似乎並不堅持原始查詢。
Commands completed successfully.
不說
Name Schema Urn CreateDate Owner IsEncrypted ImplementationType IsNativelyCompiled TestCs dbo Server[@Name='DESKTOP-602CJ92\ 2019-01-28 20:05:28.220 dbo 0 1 0
發現錯誤
SELECT * FROM sys.plan_guides CROSS APPLY sys.fn_validate_plan_guide (plan_guide_id) WHERE name = 'Filtering2'
嘗試使用不同的方法將 XML 計劃添加到計劃指南時發生相同的錯誤
DECLARE @xml_showplan nvarchar(max); SET @xml_showplan = (SELECT query_plan FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st CROSS APPLY sys.dm_exec_text_query_plan(qs.plan_handle, DEFAULT, DEFAULT) AS qp WHERE st.text LIKE N'%uses_native_compilation%' and st.text like '%COLLATE%'
我的猜測是它的縮寫:
NO_PLAN:查詢處理器無法生成查詢計劃,因為無法驗證強制計劃對查詢是否合法
我可能正在做一些計劃指南無法做到的事情。