Проблема оптимизатора запросов SQL Server - PullRequest
0 голосов
/ 09 марта 2011

То, как SQL-сервер оптимизирует запрос, приводит к его поломке. Это иллюстрируется двумя примерами ниже:

SELECT distinct ET.ElementName, ET.Shared, CONVERT(float,ED.Value), ED.SheetSetVersionID, ED.SheetDataID
FROM tElementData ED 
INNER JOIN tElementTemplate ET 
ON ED.ElementTemplateID = ET.ElementTemplateID 
AND ET.ElementName like 'RPODCQRated'

Приведенный выше запрос работает нормально, но это не тот запрос, который мне нужно выполнить.

SELECT distinct ET.ElementName, ET.Shared, CONVERT(float,ED.Value),    ED.SheetSetVersionID, ED.SheetDataID
FROM tElementData ED 
INNER JOIN tElementTemplate ET 
ON ED.ElementTemplateID = ET.ElementTemplateID 
AND ET.ElementName like 'RPODCQRated'
AND CONVERT(float,ED.Value) = 0.006388

Приведенный выше запрос выдает исключение, в котором говорится, что он не может преобразовать значение nvarchar в число с плавающей точкой. tElementData.Value является полем nvarchar (500), и некоторые записи не имеют числовых значений, но все значения, где tElementTemplate = 'RPODCQRated' могут быть преобразованы в число с плавающей запятой, как показывает верхний запрос. Кажется, что SQL-сервер в своей мудрости применяет CONVERT (float, ED.Value), прежде чем он пытается присоединиться. Мне нужно, чтобы второй запрос работал как-то, я могу переписать его, но есть ограничения на то, что я могу сделать, не переписывая весь слой данных существующего приложения.

Вещи, которые я пробовал, которые не помогают: перемещение последних критериев в предложение where, а не соединение, создание первого запроса в CTE и применение предложения where к CTE, создание скалярной функции, которая вызывает IsNumeric для данные перед попыткой конвертации.

Единственный недостаток, который я смог получить, - это вставить все данные во временную таблицу, а затем применить условие where к временной таблице. К сожалению, для реализации этого в качестве решения потребовалось бы обширное рефакторинг уровня данных приложения, чтобы устранить скрытую ошибку при поиске определенных записей.

Есть идеи?

Ответы [ 3 ]

3 голосов
/ 09 марта 2011

Единственный способ в SQL для обеспечения линейной оценки - использовать оператор Case

SELECT distinct ET.ElementName, ET.Shared, CONVERT(float,ED.Value), ED.SheetSetVersionID, ED.SheetDataID 
FROM tElementData ED  
INNER JOIN tElementTemplate ET  
ON ED.ElementTemplateID = ET.ElementTemplateID  
AND ET.ElementName like 'RPODCQRated' 
AND CASE(WHEN ET.ElementName like 'RPODCQRated' then CONVERT(float,ED.Value) else 0 end) = 0.006388 

Это, вероятно, вызовет повторную проверку ElementName, но, насколько я знаю, это единственный способобеспечить порядок оценки.

Если, конечно, вы не переместите все eval из запроса, вложите результаты в CTP и выполните приведение результатов.

0 голосов
/ 10 марта 2011

Я решил эту проблему с помощью табличной функции.Имя элемента, оператор и правое значение последнего предложения соединения генерируются динамически.Я создал приведенный ниже tvf и заменил соответствующую часть оператора select на вызов tvf.

CREATE FUNCTION tvfAdvancedSearch
(
    @TemplateType nvarchar(500)
)
RETURNS 
@Results TABLE 
(   
    ElementName nvarchar(50),
    Shared tinyint, 
    Value NVARCHAR(500), 
    SheetSetVersionID int, 
    SheetDataID int
)
AS
BEGIN
    INSERT INTO @Results
    SELECT distinct ET.ElementName, ET.Shared, ED.Value, ED.SheetSetVersionID, ED.SheetDataID
    FROM tElementData ED 
    INNER JOIN tElementTemplate ET 
        ON ED.ElementTemplateID = ET.ElementTemplateID 
        AND ET.ElementName like @TemplateType   
    RETURN 
END
GO

Я также хотел бы отметить, что ответ Брайана Рудольфа также работал, но я уже реализовал это решение раньшеЯ видел его пост.

0 голосов
/ 09 марта 2011

я бы попробовал разбить его на что-то вроде этого:

;with a as
(

SELECT distinct
    ET.ElementName,
    ET.Shared,
    CONVERT(float, ED.Value),
    ED.SheetSetVersionID,
    ED.SheetDataID
FROM
    tElementData ED
    INNER JOIN tElementTemplate ET
        ON ED.ElementTemplateID = ET.ElementTemplateID
           AND ET.ElementName like 'RPODCQRated'
)
select *
from a
where CONVERT(float, ED.Value) = 0.006388

или вы пробовали "где ED.Value = '0.006388' или что-то подобное, эквивалентное varchar?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...