觸發此警告的原因:表達式中的類型轉換可能會影響查詢計劃選擇中的“CardinalityEstimate”
使用 SQL Server 2016,我試圖了解為什麼在執行此 T-SQL 語句時收到此警告(我選擇 table 變數以方便測試。這發生在具有
int
類型列的 DB 表中):declare @test as table( col1 int ) insert into @test (col1) values(30500600) select LEFT(test.col1, 2) from @test as test
30
按預期返回,但在檢查執行計劃時,我看到一條警告SELECT
語句,內容如下:表達式中的類型轉換 (CONVERT_IMPLICIT(varchar(12),
$$ test $$.$$ col1 $$,0)) 可能會影響查詢計劃選擇中的“CardinalityEstimate”
如果我在沒有從表中拉出的情況下執行相同的操作:
select LEFT(30500600, 2)
30
按預期返回,執行計劃中沒有警告。這兩個語句都應該
LEFT()
在int
類型上執行,所以我不明白為什麼一個返回警告而另一個沒有。這裡發生了什麼?編輯:
我嘗試將
col1
數據類型聲明更改為varchar
並清除錯誤。但這仍然不能向我解釋為什麼select LEFT(30500600, 2)
如果我將 anint
直接傳遞給LEFT()
函式,它本身不會引起警告。我嘗試
cast
在varchar
原始查詢中:LEFT(cast(test.col1 as varchar(12)), 2)
返回相同的警告。可能重複
連結的重複項表明計算列是該使用者的問題。我的範例中沒有計算列,所以這不是問題。這將我引向關於使用函式隱式轉換為字元串類型的答案的第二部分,該
CONCAT
函式也相同LEFT
。在我上面編輯的第二段中,我曾經CAST
明確轉換為,varchar
所以我認為不會發生轉換?我顯然在這裡遺漏了一些東西。
此查詢中沒有“類型轉換/基數估計”警告的原因:
SELECT LEFT(30500600, 2);
…是因為沒有基數估計。 它是一個常量表達式,被傳遞給確定性函式——保證只返回一個“行”。我認為解釋就這麼簡單,因為警告更多的是關於潛在的基數問題(而不僅僅是類型轉換的簡單存在)。
如果我得到該語句的估計執行計劃,它只是一個“選擇不查詢”元素:
<?xml version="1.0" encoding="utf-16"?> <ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.518" Build="13.0.5081.1" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan"> <BatchSequence> <Batch> <Statements> <StmtSimple StatementCompId="1" StatementId="1" StatementText="select LEFT(30500600, 2)" StatementType="SELECT WITHOUT QUERY" RetrievedFromCache="false" /> </Statements> </Batch> </BatchSequence> </ShowPlanXML>
對於它的價值,即使是表變數版本也不會在 SQL Server 2017中顯示警告(因為當轉換不可能影響基數估計時,它確實是一個毫無意義的警告 - 如您的範例所示)。
需要明確的是,這個警告並不總是毫無意義的。舉個例子:
SELECT message_id INTO #SomeNumbers from sys.messages; SELECT * FROM #SomeNumbers WHERE LEFT(message_id, 2) = '50';
這會將 280,192 行放入臨時表中。SELECT 查詢有這個警告,警告是合法的。SQL Server 估計有 28,019.2 個匹配行(佔表的 10%),而實際上只有 2,156 個匹配行(<1% 的表)。
關於您將此輸入轉換為
LEFT
函式的範例,請注意警告已從略微更改CONVERT_IMPLICIT
為 justCONVERT
:表達式中的類型轉換 (CONVERT(varchar(12),
$$ test $$.$$ col1 $$,0)) 可能會影響查詢計劃選擇中的“CardinalityEstimate”
因此,您只是用顯式轉換替換隱式轉換,這仍然需要警告。