Страница 1 из 1

Собственный поиск объектов (LSQuery)

Добавлено: 02 сен 2009, 15:39
Disillusioned
В этой теме предлагаю обмениваться своими достижениями и соображениями в части организации поиска объектов при помощи объекта LSQuery.

Для Sybase SQL Anywhere 10 есть(была) проблема с производительностью стандартного поиска объектов по нескольким атрибутам. Если же между атрибутами есть OR, проблема производительности должна быть актуальна для всех СУБД.
Благодаря приведенному ниже варианту, время поиска удалось существенно снизить, в ряде случаев, более чем на порядок.
Удалось избежать пагубного влияния OR между атрибутами на производительность поиска.
"NOT IN" вместо "<>" также способствует росту производительности.

Начнем со скрипта.

Код: Выделить всё

Option Explicit
Sub Search()
  dim SearchDS,Cond,i,iOpen,iClose,attr_cnt,lAttribID
  dim iLO,cLO,rValue
  if LSQuery.IsCustomSet("LsObjByAttrib") then
    set SearchDS=LSQuery.CustomParam("LsObjByAttrib")
    if SearchDS.Count>1 then
      attr_cnt=0
      iLO=0
      iOpen=0
      For i=1 To SearchDS.Count
        Set Cond=SearchDS.Item(i)
        if Cond.lType="A" then attr_cnt=attr_cnt+1
        if attr_cnt=0 then
          iLO=i
          iOpen=iOpen+Cond.bOpen-Cond.bClose
        end if
      Next
      if attr_cnt>1 and iLO>0 and iOpen=0 then
        For i=1 to ILO
          set Cond=SearchDS.Item(i)
          rValue=PrepareStrValue(Cond.rValue)
          if (Cond.Oper="like" or Cond.Oper="not like") and right(rValue,1)<>"%" then rValue=rValue+"%"
          Select Case Cond.lValue
            Case "D"              
              Select Case Cond.Oper
                Case "exists"
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_reference_view.description > '' "+_
                    +String(Cond.bClose,")")
                Case "not exists"
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_reference_view.description = '' "+_
                    +String(Cond.bClose,")")
                Case Else
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_reference_view.description "+Cond.Oper+" '"+_
                    rValue+"' "+String(Cond.bClose,")")
              End Select
            Case "T"
              Select Case Cond.Oper
                Case "exists"
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_type_view.description > '' "+_
                    +String(Cond.bClose,")")
                Case "not exists"
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_type_view.description = '' "+_
                    +String(Cond.bClose,")")
                Case Else
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_type_view.description "+Cond.Oper+" '"+_
                    rValue+"' "+String(Cond.bClose,")")
              End Select
            Case "M"
              Select Case Cond.Oper
                Case "exists"
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_type_view.mnemo > '' "+_
                    +String(Cond.bClose,")")
                Case "not exists"
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_type_view.mnemo = '' "+_
                    +String(Cond.bClose,")")
                Case Else
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_type_view.mnemo "+Cond.Oper+" '"+_
                    rValue+"' "+String(Cond.bClose,")")
              End Select
            Case "C"
              Select Case Cond.Oper
                Case "exists"
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_type_view.object_type > '' "+_
                    +String(Cond.bClose,")")
                Case "not exists"
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_type_view.object_type = '' "+_
                    +String(Cond.bClose,")")
                Case Else
                  cLO=cLO+String(Cond.bOpen,"(")+_
                    "lsdbo.object_type_view.object_type "+Cond.Oper+" '"+_
                    rValue+"' "+String(Cond.bClose,")")
              End Select            
          End Select
          cLO=cLO+" "+Cond.Logic+" "
        Next
      else
        iLO=0
      end if
      iLO=iLO+1
      if attr_cnt>1 then
        LSTransaction.Execute("DELETE FROM lsdbo.aln_misc_LSQueryCond")
        For i=iLO To SearchDS.Count
          Set Cond=SearchDS.Item(i)
          if i=iLO then iOpen=1 else iOpen=0
          if i=SearchDS.Count then iClose=1 else iClose=0
          if IsEmpty(Cond.lAttribID) then lAttribID=0 else lAttribID=Cond.lAttribID
          LSTransaction.Execute(_
            "INSERT INTO lsdbo.aln_misc_LSQueryCond(sNum,bOpen,lType,lValue,lAttribID,Oper,rValue,bClose,Logic,DataType)"+_
            " VALUES("+CStr(i*1000)+","+CStr(Cond.bOpen+iOpen)+",'"+Cond.lType+"','"+Cond.lValue+"',"+_
            CStr(lAttribID)+",'"+Cond.Oper+"','"+PrepareStrValue(Cond.rValue)+"',"+_
            CStr(Cond.bClose+iClose)+",'"+Cond.Logic+"','"+Chr(Cond.DataType)+"')")
        Next
        call LSQuery.CustomWhere("LsObjByAttrib",_
          cLO+"lsdbo.object_reference_view.id in(SELECT id FROM lsdbo.aln_misc_LSQuery())")
      end if
    end if
  end if
End Sub
Function PrepareStrValue(str_val)
  str_val=replace(str_val,"'","''")
  str_val=replace(str_val,vbnewline,"\x0D\x0A")
  PrepareStrValue=str_val
End Function
Условия поиска сохраняются в таблице

Код: Выделить всё

CREATE GLOBAL TEMPORARY TABLE "LSDBO"."aln_misc_LSQueryCond" (
    "sNum"                           integer NOT NULL
   ,"bOpen"                          integer NULL
   ,"lType"                          char(1) NULL
   ,"lValue"                         char(1) NULL
   ,"lAttribID"                      numeric(18,0) NULL
   ,"Oper"                           varchar(20) NULL
   ,"rValue"                         varchar(255) NULL
   ,"bClose"                         integer NULL
   ,"Logic"                          varchar(20) NULL
   ,"DataType"                       char(1) NULL
   ,PRIMARY KEY ("sNum") 
) NOT TRANSACTIONAL
Далее текст поисковых процедур на WatcomSQL:
№1

Код: Выделить всё

ALTER PROCEDURE "LSDBO"."aln_misc_LSQuery"()
RESULT(id numeric(18))
BEGIN
	declare local temporary table #res(
		sNum integer,
		id numeric(18),
	)not transactional;
	declare @sNum1 integer;
	declare @sNum2 integer;
	declare @SNum_res integer;
	declare @lType1 char(1);
	declare @lType2 char(1);
	declare @Logic varchar(20);
	declare @Logic_res varchar(20);
	declare @bOpen_res integer;
	declare @bClose_res integer;
	declare @lAttribID1 numeric(18);
	declare @lAttribID2 numeric(18);
	declare @lValue1 char(1);
	declare @lValue2 char(1);
	declare @rValue1 varchar(255);
	declare @rValue2 varchar(255);
	declare @Oper1 varchar(20);
	declare @Oper2 varchar(20);
	declare @DataType1 char(1);
	declare @DataType2 char(1);

	create index aln_misc_LSQuery_1_ndx on #res(sNum);

	//Убираем избыточные скобки
	update lsdbo.aln_misc_LSQueryCond set
		bOpen=bOpen-(if bOpen<bClose then bOpen else bClose endif),
		bClose=bClose-(if bOpen<bClose then bOpen else bClose endif)
		where bOpen>0 and bClose>0;
	while exists(select sNum from lsdbo.aln_misc_LSQueryCond where bClose>0)loop
		//Определяем номера условий/множеств
		select min(sNum) into @sNum2 from lsdbo.aln_misc_LSQueryCond where bClose>0;
		select max(sNum) into @sNum1 from lsdbo.aln_misc_LSQueryCond where sNum<@sNum2;		
		set @sNum_res=@sNum1-1;
		select first bOpen,lType,lValue,lAttribID,Oper,rValue,Logic,DataType
			into @bOpen_res,@lType1,@lValue1,@lAttribID1,@Oper1,@rValue1,@Logic,@DataType1
			from lsdbo.aln_misc_LSQueryCond where sNum=@sNum1;
		select first bClose,lType,lValue,lAttribID,Oper,rValue,Logic,DataType
			into @bClose_res,@lType2,@lValue2,@lAttribID2,@Oper2,@rValue2,@Logic_res,@DataType2
			from lsdbo.aln_misc_LSQueryCond where sNum=@sNum2;
		//Обрабатываем связку @cur_sNum и @prev_sNum
		case @Logic
			when 'and' then
				insert into #res(sNum,id)
				  select @sNum_res,dt1.id from
					(select id from aln_misc_LSQuerySingleSet(@lType1,@lValue1,
						@lAttribID1,@Oper1,@rValue1,@DataType1)) as dt1(id)
					join
					(select id from aln_misc_LSQuerySingleSet(@lType2,@lValue2,
						@lAttribID2,@Oper2,@rValue2,@DataType2)) as dt2(id)
					on dt1.id=dt2.id;
			when 'or' then
				insert into #res(sNum,id)
					select @sNum_res,id from aln_misc_LSQuerySingleSet(@lType1,@lValue1,
						@lAttribID1,@Oper1,@rValue1,@DataType1)
					union all
					select @sNum_res,id from aln_misc_LSQuerySingleSet(@lType2,@lValue2,
						@lAttribID2,@Oper2,@rValue2,@DataType2);
			when 'and not' then
				insert into #res(sNum,id)
 				  select @sNum_res,dt1.id from
					(select id from aln_misc_LSQuerySingleSet(@lType1,@lValue1,
						@lAttribID1,@Oper1,@rValue1,@DataType1)) as dt1(id)
					left outer join
					(select id from aln_misc_LSQuerySingleSet(@lType2,@lValue2,
						@lAttribID2,@Oper2,@rValue2,@DataType2)) as dt2(id)
					on dt1.id=dt2.id
					where dt2.id is null;
			when 'or not' then
				insert into #res(sNum,id)
					select @sNum_res,id from aln_misc_LSQuerySingleSet(@lType1,@lValue1,
						@lAttribID1,@Oper1,@rValue1,@DataType1)
					union all
					select @sNum_res,id from object_reference
						where id not in(select id from aln_misc_LSQuerySingleSet(@lType2,@lValue2,@lAttribID2,@Oper2,@rValue2,@DataType2));
		end case;
		//Заменяем обработанные условия/множества полученным результаттом
		insert into lsdbo.aln_misc_LSQueryCond(sNum,lType,lAttribID,bOpen,bClose,Logic)
			values(@sNum_res,'_',@sNum_res,@bOpen_res,@bClose_res,@Logic_res);
		delete from lsdbo.aln_misc_LSQueryCond where sNum in(@sNum1,@sNum2);
		//Убираем избыточные скобки
		update lsdbo.aln_misc_LSQueryCond set
			bOpen=bOpen-(if bOpen<bClose then bOpen else bClose endif),
			bClose=bClose-(if bOpen<bClose then bOpen else bClose endif)
			where bOpen>0 and bClose>0;
	end loop;
	select id from #res where sNum=@sNum_res;
END
№2

Код: Выделить всё

ALTER PROCEDURE "LSDBO"."aln_misc_LSQuerySingleSet"(in @lType char(1),in @lValue char(1),in @lAttribID numeric(18),
	in @Oper varchar(20),in @rValue varchar(255),in @DataType char(1))
RESULT (id numeric(18))
BEGIN
case @lType	
	When'A' then
		case @Oper
			when 'exists' then
				SELECT object_id as id FROM lsdbo.attrib_value force index(attrib_key1) WHERE attrib_id=@lAttribID;
			when 'not exists' then
				SELECT id FROM lsdbo.object_reference
					WHERE id NOT IN(SELECT object_id FROM lsdbo.attrib_value force index(attrib_key1) WHERE attrib_id=@lAttribID);
			when 'like'	Then		
				case @DataType
					when 'S' Then
						set @rValue=(if coalesce(right(@rValue,1),'')<>'%' then @rValue+'%' else @rValue endif);
						SELECT av.object_id as id
							FROM lsdbo.value_string as vt force index(attrib_ndx3) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value like @rValue;
					when 'N' Then
						SELECT av.object_id as id
							FROM lsdbo.value_numeric as vt force index(attrib_ndx7) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value like cast(@rValue as double);
					when 'T' Then
						SELECT av.object_id as id
							FROM lsdbo.value_datetime as vt force index(attrib_ndx4) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value like convert(datetime,@rValue,104);
				end case;
			when 'not like'	Then		
				case @DataType
					when 'S' Then
						set @rValue=(if coalesce(right(@rValue,1),'')<>'%' then @rValue+'%' else @rValue endif);
						SELECT av.object_id as id
							FROM lsdbo.value_string as vt force index(attrib_ndx3) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value not like @rValue;
					when 'N' Then
						SELECT av.object_id as id
							FROM lsdbo.value_numeric as vt force index(attrib_ndx7) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value not like cast(@rValue as double);
					when 'T' Then
						SELECT av.object_id as id
							FROM lsdbo.value_datetime as vt force index(attrib_ndx4) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value not like convert(datetime,@rValue,104);
				end case;
			when '=' Then
				case @DataType
					when 'S' Then
						SELECT av.object_id as id
							FROM lsdbo.value_string as vt force index(attrib_ndx3) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value = @rValue;
					when 'N' Then
						SELECT av.object_id as id
							FROM lsdbo.value_numeric as vt force index(attrib_ndx7) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value = cast(@rValue as double);
					when 'T' Then
						SELECT av.object_id as id
							FROM lsdbo.value_datetime as vt force index(attrib_ndx4) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value = convert(datetime,@rValue,104);
				end case;
			when '>' Then
				case @DataType
					when 'S' Then
						SELECT av.object_id as id
							FROM lsdbo.value_string as vt force index(attrib_ndx3) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value > @rValue;
					when 'N' Then
						SELECT av.object_id as id
							FROM lsdbo.value_numeric as vt force index(attrib_ndx7) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value > cast(@rValue as double);
					when 'T' Then
						SELECT av.object_id as id
							FROM lsdbo.value_datetime as vt force index(attrib_ndx4) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value > convert(datetime,@rValue,104);
				end case;
			when '>=' Then
				case @DataType
					when 'S' Then
						SELECT av.object_id as id
							FROM lsdbo.value_string as vt force index(attrib_ndx3) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value >= @rValue;
					when 'N' Then
						SELECT av.object_id as id
							FROM lsdbo.value_numeric as vt force index(attrib_ndx7) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value >= cast(@rValue as double);
					when 'T' Then
						SELECT av.object_id as id
							FROM lsdbo.value_datetime as vt force index(attrib_ndx4) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value >= convert(datetime,@rValue,104);
				end case;
			when '<' Then
				case @DataType
					when 'S' Then
						SELECT av.object_id as id
							FROM lsdbo.value_string as vt force index(attrib_ndx3) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value < @rValue;
					when 'N' Then
						SELECT av.object_id as id
							FROM lsdbo.value_numeric as vt force index(attrib_ndx7) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value < cast(@rValue as double);
					when 'T' Then
						SELECT av.object_id as id
							FROM lsdbo.value_datetime as vt force index(attrib_ndx4) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value < convert(datetime,@rValue,104);
				end case;
			when '<=' Then
				case @DataType
					when 'S' Then
						SELECT av.object_id as id
							FROM lsdbo.value_string as vt force index(attrib_ndx3) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value <= @rValue;
					when 'N' Then
						SELECT av.object_id as id
							FROM lsdbo.value_numeric as vt force index(attrib_ndx7) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value <= cast(@rValue as double);
					when 'T' Then
						SELECT av.object_id as id
							FROM lsdbo.value_datetime as vt force index(attrib_ndx4) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value <= convert(datetime,@rValue,104);
				end case;
			when '<>' Then
				case @DataType
					when 'S' Then
						SELECT av.object_id as id
							FROM lsdbo.value_string as vt force index(attrib_ndx3) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value not in(@rValue);
					when 'N' Then
						SELECT av.object_id as id
							FROM lsdbo.value_numeric as vt force index(attrib_ndx7) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value not in(cast(@rValue as double));
					when 'T' Then
						SELECT av.object_id as id
							FROM lsdbo.value_datetime as vt force index(attrib_ndx4) JOIN lsdbo.attrib_value as av force index(attrib_value_av_ndx)
								on vt.attrib_id=av.attrib_id and vt.id=av.value_id
							WHERE vt.attrib_id=@lAttribID and vt.value not in(convert(datetime,@rValue,104));
				end case;
		end case;
	when 'O' then
		case @lValue
			when 'D' then
				case @Oper
					when 'exists' then
						SELECT id FROM lsdbo.object_reference force index(object_reference_desc_ndx) where description>'';
					when 'not exists' then
						SELECT id FROM lsdbo.object_reference force index(object_reference_desc_ndx) where description='';;
					when 'like' then
						set @rValue=(if coalesce(right(@rValue,1),'')<>'%' then @rValue+'%' else @rValue endif);
						SELECT id FROM lsdbo.object_reference force index(object_reference_desc_ndx) where description like @rValue;
					when 'not like' then
						set @rValue=(if coalesce(right(@rValue,1),'')<>'%' then @rValue+'%' else @rValue endif);
						SELECT id FROM lsdbo.object_reference force index(object_reference_desc_ndx) where description not like @rValue;
					when '=' then
						SELECT id FROM lsdbo.object_reference force index(object_reference_desc_ndx) where description = @rValue;
					when '>' then
						SELECT id FROM lsdbo.object_reference force index(object_reference_desc_ndx) where description > @rValue;
					when '>=' then
						SELECT id FROM lsdbo.object_reference force index(object_reference_desc_ndx) where description >= @rValue;
					when '<' then
						SELECT id FROM lsdbo.object_reference force index(object_reference_desc_ndx) where description < @rValue;
					when '<=' then
						SELECT id FROM lsdbo.object_reference force index(object_reference_desc_ndx) where description <= @rValue;
					when '<>' then
						SELECT id FROM lsdbo.object_reference force index(object_reference_desc_ndx) where description not in(@rValue);
				end case;
			when 'T' then
				case @Oper
					when 'exists' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.description > '';
					when 'not exists' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.description='';;
					when 'like' then
						set @rValue=(if coalesce(right(@rValue,1),'')<>'%' then @rValue+'%' else @rValue endif);
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.description like @rValue;
					when 'not like' then
						set @rValue=(if coalesce(right(@rValue,1),'')<>'%' then @rValue+'%' else @rValue endif);
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.description not like @rValue;
					when '=' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.description = @rValue;
					when '>' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.description > @rValue;
					when '>=' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.description >= @rValue;
					when '<' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.description < @rValue;
					when '<=' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.description <= @rValue;
					when '<>' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.description not in(@rValue);
				end case;
			when 'M' then
				case @Oper
					when 'exists' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.mnemo > '';
					when 'not exists' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.mnemo='';;
					when 'like' then
						set @rValue=(if coalesce(right(@rValue,1),'')<>'%' then @rValue+'%' else @rValue endif);
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.mnemo like @rValue;
					when 'not like' then
						set @rValue=(if coalesce(right(@rValue,1),'')<>'%' then @rValue+'%' else @rValue endif);
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.mnemo not like @rValue;
					when '=' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.mnemo = @rValue;
					when '>' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.mnemo > @rValue;
					when '>=' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.mnemo >= @rValue;
					when '<' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.mnemo < @rValue;
					when '<=' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.mnemo <= @rValue;
					when '<>' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.mnemo not in(@rValue);
				end case;
			when 'C' then
				case @Oper
					when 'exists' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.object_type > '';
					when 'not exists' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.object_type='';;
					when 'like' then
						set @rValue=(if coalesce(right(@rValue,1),'')<>'%' then @rValue+'%' else @rValue endif);
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.object_type like @rValue;
					when 'not like' then
						set @rValue=(if coalesce(right(@rValue,1),'')<>'%' then @rValue+'%' else @rValue endif);
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.object_type not like @rValue;
					when '=' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.object_type = @rValue;
					when '>' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.object_type > @rValue;
					when '>=' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.object_type >= @rValue;
					when '<' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.object_type < @rValue;
					when '<=' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.object_type <= @rValue;
					when '<>' then
						SELECT o.id	FROM lsdbo.object_type as ot JOIN lsdbo.object_reference as o force index(object_reference)
							on ot.id=o.type_id where ot.object_type not in(@rValue);
				end case;
		end case;
	when '_' then
		select id from #res where sNum=@lAttribID;
end case;
END

Re: Собственный поиск объектов (LSQuery)

Добавлено: 03 сен 2009, 06:45
Александр
вопрос - а что за объект LSQuery? вообще нигде не нашел, и второе а в чем идея ускорения - в двух словах?

Re: Собственный поиск объектов (LSQuery)

Добавлено: 03 сен 2009, 10:14
Disillusioned
LSQuery используется для подмены стандартного поиска Лоции собственным. Описан в руководстве "Скрипты".
Принцип стандартного поиска Лоции состоит в том, что все условия записываются в условия WHERE одного SELECTа. Т.е. используется принцип "все яйца в одну корзину", что удобно, но не всегда эффективно. Соответственно, в ряде случаев получаются такие запросы, что оптимизатор на них отрабатывает не лучшим образом. Особенно, если в условиях есть ИЛИ. Резюме: отличные результаты для большинства простых запросов и зачастую неудовлетворительная производительность поиска со сложными условиями.
Суть моего подхода: для каждой строки условия отдельно вычисляется множество удовлетворяющих ему объектов, затем множества пересекаются INNER JOIN (И) LEFT OUTER JOIN (И НЕ) или объединяются UNION (ИЛИ) (ИЛИ НЕ). Для получения каждого множества используются простые запросы, проблем с оптимизацией которых не возникает. Т.е. используется принцип "разделяй и властвуй". Резюме: удовлетворительное время поиска для запросов любой сложности при большей ресурсоемкости (относительно высокий процент утилизации процессора сервера СУБД).
Для поисковых запросов, где больше одного атрибута использую свой метод, для остальных стандартные средства поиска. Плюс, при возможности, условия по типам и описаниям объектов стараюсь выводить в условие WHERE т.к. обработка этих условий как отдельных множеств наиболее ресурсоемка.

Re: Собственный поиск объектов (LSQuery)

Добавлено: 03 сен 2009, 10:53
Александр
Спасибо!
...в мануале и не посмотрел :wink: Знаешь - был бы отладчик нормальный - я бы лично с удовольствием посмотрел твой код (wathes) по шагам... вообще с удивлением узнал что в окне выбора объектов есть скрипты - никогда этим окном не пользуемся вообще. А идея - то что надо!
ps
а функций оказывается действительно много добавили - еще бы примеров конкретных с комментариями...
глядишь и уйдут в прошлое макросы и настанет эпоха водолея.. упс.. скриптов и vba :wink:

Re: Собственный поиск объектов (LSQuery)

Добавлено: 27 июн 2010, 17:04
Александр
попробовал скрипт в поиске объектов - есть пара вопросов, отвлеченных...
как я понял скрипт просто расширяет секцию where... у стандартного запроса
1 можно ли в скрипте, здесь, перед началом допустим поиска организовать выбор дополнительных условий через msgbox - типа выберите то или это, или в принципе - хотите использовать скрипт или нет... - у меня на msgbox как таковой ругается - т.е. здесь интерпретатор обрезанный или... что?
в плане реализации выбора например
-дочерние объекты
-родительские объекты
-простой поиск
2 а если выбор дополнительных условий нельзя организовать в виде диалога, только через сохранение запросов окна выбора объектов - какой вообще смысл этого функционала? - если настройка скрипта - одна (одна процедура) на весь выбор объектов (Общие параметры БД) на все сохраненные запросы, пусть расширенная и оптимизированная скриптом - но по прежнему одна на всех...
что-то я не понимаю всей прелести такого подхода- или тут еще что-то есть интересное и где-то можно оперативно переключать/выбирать ту или иную процедуру скрипта - какой-то выпадающий список или что-то еще?

Re: Собственный поиск объектов (LSQuery)

Добавлено: 28 июн 2010, 08:21
Disillusioned
у меня на msgbox как таковой ругается
Не работают здесь диалоговые окна.
что-то я не понимаю всей прелести такого подхода- или тут еще что-то есть интересное и где-то можно оперативно переключать/выбирать ту или иную процедуру скрипта - какой-то выпадающий список или что-то еще?
Создавайте служебные атрибуты, не привязанные к типам объектов, с редактированием "список", добавляйте в них нужные Вам значения. Обрабатывайте эти атрибуты отдельно от остальных. Вот и будут Вам выпадающие списки и иные процедуры скрипта. А вообще, рекомендую определиться: а зачем конкретно Вам нужны собственные поисковые процедуры? Глядишь под конкретную задачу и решение найдется... Мне например, LSQuery очень пригодился для оптимизации скорости поиска, т.к. некоторые варианты поиска с большим количеством атрибутов и, особенно, с условием ИЛИ у меня отрабатывали за десятки секунд, а сейчас менее секунды.

Re: Собственный поиск объектов (LSQuery)

Добавлено: 28 июн 2010, 09:15
Александр
Создавайте служебные атрибуты, не привязанные к типам объектов, с редактированием "список", добавляйте в них нужные Вам значения.
не вопрос, а выбор визуальный как сделать? что я хочу такой алгоритм/процедуру(функцию) скрипта - поиска применить или такой или не применять вообще....
весь вопрос именно в этом

если скрипт нужен просто для оптимизации поиска ввиду загруженности разработчика - Лоция дала инструмент - ты на его основе сделал работу по оптимизации
Мне например, LSQuery очень пригодился для оптимизации скорости поиска
- и Лоция может включить твой код в базовую поставку - это одно. Просто общая процедура для всей базы сделанная клиентом. По аналогии с DBPrint.

или есть какое то специализированное применение скрипта при выборе объекта с привязкой не к одному методу поиска а к нескольким - с возможностью выбора? Может можно создать несколько Именованных Окон выбора со своими скриптами - по аналогии с Именованной Подборкой?
Типа -это окно выбора - умеет хорошо отбирать дочерние объекты, а это просто делать поиск по базе без привязкам к иерархии... вот в этом плане

Re: Собственный поиск объектов (LSQuery)

Добавлено: 28 июн 2010, 10:03
Disillusioned
1. Создаем строковые атрибуты "Параметр поиска 1" и "Параметр поиска 2" и т.д. Редактирование "список". В список значений добавляем все возможные варианты этих параметров.
2. В поисковом скрипте анализируем наличие в условиях поиска атрибутов из п.1. Если их нет, то идем по некоему варианту "по умолчанию". Если какие-то значения параметра поиска установлены, то анализируя их значения, активируем те или иные функции и алгоритмы поиска.
3. А теперь по использованию атрибутов-параметров поиска
3.1. Если пользователю нужно самому выбрать параметр поиска, то создаем поисковую форму (если опыта с поисковыми формами нет, почитайте хелп и поэкспериментируйте), в которой помимо атрибутов искомых объектов добавляем атрибуты-параметры, созданные на шаге 1.
3.2. Если нужно жестко задать некий вариант поиска, указываем в условиях отбора объекта нужное значение атрибута-параметра и пользователь знать о нем не будет ничего и изменить его не сможет.

В п.1.-3. вроде как все визуально и применимо для большинства реальных потребностей.

Пример применения такого подхода мы уже обсуждали в http://www.lplm.ru/phpBB2/viewtopic.php?f=18&t=631
Может можно создать несколько Именованных Окон выбора со своими скриптами - по аналогии с Именованной Подборкой?
В документации Именованные Окна выбора называются формами поиска. Далее см. выше.
если скрипт нужен просто для оптимизации поиска ввиду загруженности разработчика - Лоция дала инструмент - ты на его основе сделал работу по оптимизации
Мне кажется, что реализация моего оптимизированного варианта поиска заняла бы у Лоции Софт гораздо меньше времени, чем разработка LSQuery. Хотя, конечно, Вы можете со мной не согласиться - на то и холивар.
Типа -это окно выбора - умеет хорошо отбирать дочерние объекты, а это просто делать поиск по базе без привязкам к иерархии... вот в этом плане
Судя по всему, опыт организации поиска объектов стандартными средствами Лоции у Вас не очень большой... На мой взгляд, поиск Лоции - это одна из сильных ее сторон, насколько я могу судить по шапочному знакомству с некоторыми из ее конкурентов.