Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 пятничный план  [new]
план
Guest
Есть запрос:
select sum(cast(replace(t.zField1,' ','') as decimal(25,2))) as zField1    
from ztable t    
where  isnumeric(t.zField1) = 1      
	and len(t.zField1) > 0      
	and len(t.zField1) < 20      
	and t.zField1 not like '%[^0-9. +-]%'     
	and not (t.zField1 like '%[^0-9]%' and len(t.zField1) = 1)      
	and t.zField1 not like '%,%'

Есть план запроса:
+

|--Compute Scalar(DEFINE:([Expr1002]=CASE WHEN [Expr1019]=(0) THEN NULL ELSE [Expr1020] END))
|--Stream Aggregate(DEFINE:([Expr1019]=COUNT_BIG([Expr1010]), [Expr1020]=SUM([Expr1010])))
|--Filter(WHERE:([Expr1011]=(1) AND [Expr1012]>(0) AND [Expr1012]<(20) AND NOT [Expr1013] like '%[^0-9. +-]%' AND (NOT [Expr1013] like '%[^0-9]%' OR [Expr1012]<>(1)) AND NOT [Expr1013] like '%,%'))
|--Compute Scalar(DEFINE:([Expr1010]=CONVERT(decimal(25,2),replace([bla].[dbo].[ztable].[zField1] as [t].[zField1],' ',''),0), [Expr1011]=isnumeric([bla].[dbo].[ztable].[zField1] as [t].[zField1]), [Expr1012]=len([bla].[dbo].[ztable].[zField1] as [t].[zField1]), [Expr1013]=[bla].[dbo].[ztable].[zField1] as [t].[zField1]))
|--Compute Scalar(DEFINE:([t].[zField1]= [t].[zField])))
|--Clustered Index Scan(OBJECT:([bla].[dbo].[ztable].[ClsterIndex] AS [t]))

Вопрос:
Соглано плана, в начале выполняется преобразование к децималу(Expr1010), а уж потом накладывается фильтр(WHERE). И, как бы, должно упасть на ошибку: есть много строк, которые нельзя преобразовать к децималу.
В реале, запрос выполняется правильно: не падает и считает правильно.
План показывает неправильный порядок выполнения операций?
26 апр 13, 17:55    [14236468]     Ответить | Цитировать Сообщить модератору
 Re: пятничный план  [new]
SomewhereSomehow
Member

Откуда: Moscow
Сообщений: 2480
Блог
план,

У вас версия сервера больше 2000? Если да, то это объясняется так называемым "defered scalar evaluation". Начиная с 2005, выполнение скаляра может быть отложено до момента его реального использования. Это такая оптимизация, не вычислять, пока не потребуется. Кстати, на это поведение (место Compute Scalar в плане) влияет хинт force order.
Пример:
use tempdb;
go
create table t (a int primary key, b varchar(10))
insert t values (1,'1'),(2,'test');
go
set statistics profile on
go
select sum(convert(int,b)) from t 
where 
	isnumeric(b) = 1      
	and len(b) > 0      
	and b not like '%[^0-9. +-]%'     
	and not (b like '%[^0-9]%' and len(b) = 1)
	and b not like '%,%'
go
set statistics profile off
go
set statistics profile on
go
select sum(convert(int,b)) from t 
where 
	isnumeric(b) = 1      
	and len(b) > 0      
	and b not like '%[^0-9. +-]%'     
	and not (b like '%[^0-9]%' and len(b) = 1)
	and b not like '%,%'
option(force order)
go
set statistics profile off
go
--drop table t
26 апр 13, 19:18    [14236760]     Ответить | Цитировать Сообщить модератору
 Re: пятничный план  [new]
план
Guest
SomewhereSomehow,
да, вы правы: версия 2008r2. Есть ли возможность посмотреть, когда "реально " происходит преобразование, т.е. на каком шаге?
26 апр 13, 19:33    [14236806]     Ответить | Цитировать Сообщить модератору
 Re: пятничный план  [new]
SomewhereSomehow
Member

Откуда: Moscow
Сообщений: 2480
Блог
план
SomewhereSomehow,
да, вы правы: версия 2008r2. Есть ли возможность посмотреть, когда "реально " происходит преобразование, т.е. на каком шаге?

Было бы полезно иметь такую возможность, но честно говоря я о такой не знаю. Обычно, MS, судя по высказыванию Конора Канингема, при введении новой фичи, любит делать трейсфлаг, который бы отменял эту фичу. Это полезно, если у кого-то, вдруг, новая фича будет работать хуже, чем предыдущий вариант.
Для нормализации проекции (предложения select), я нашел такой флаг, это 9259. Использовал его в прошлом году, для демонстрации на sql saturday, можете поискать в блоге эту презентацию (флаг я правда там не упоминал, но план для слайда Project Normalization был сделан с помощью него).
Картинка с другого сайта.
+
use tempdb;
go
create table t (a int primary key, b varchar(10))
insert t values (1,'1'),(2,'test');
go
set statistics profile on
go
select sum(convert(int,b)) from t 
where 
	isnumeric(b) = 1      
	and len(b) > 0      
	and b not like '%[^0-9. +-]%'     
	and not (b like '%[^0-9]%' and len(b) = 1)
	and b not like '%,%'
go
set statistics profile off
go
set statistics profile on
go
select sum(convert(int,b)) from t 
where 
	isnumeric(b) = 1      
	and len(b) > 0      
	and b not like '%[^0-9. +-]%'     
	and not (b like '%[^0-9]%' and len(b) = 1)
	and b not like '%,%'
option(querytraceon 9259)
go
set statistics profile off
go

Но вот можно ли заставить выражения вычисляться там, где они обозначены в плане? Не знаю. Может быть тоже есть трейсфлаг.
Нужно копаться.
Если вас интересует еще инфа по отложенному вычислению, то я просмотрел свои заметки, и нашел, где я про это читал:
Craig Freedman's SQL Server Blog - Conversion and Arithmetic Errors
26 апр 13, 21:35    [14237090]     Ответить | Цитировать Сообщить модератору
 Re: пятничный план  [new]
план
Guest
SomewhereSomehow,
спасибо.
29 апр 13, 09:20    [14242200]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить