webForumDet fria alternativet

Optimering dyn. t-sql?

4 svar · 354 visningar · startad av Jesper T

Jesper TMedlem sedan nov. 20017 058 inlägg
#1

Jag är ingen hejjare på varken T-Sql eller dynamisk sql.
Jag använder eventuellt inbyggda funktioner och medtoder som inte är brukligt i vissa sammanhang,
ofta är det en stor nackdel och ibland så kanske det t.o.m. kan vara berikande och skapa nytänkande.
Nu till saken.
Denna dynamiska (på gränsen till hyperaktiva), sql:en har säkert många brister och min fråga är:
Om man nu skall normalisera databasen i partiklar och optimera så det står härliga till så leder
det ju även till att frågorna många gånger blir ruggigt komplexa (rätta mig om jag har fel).
Om jag nu vill presentera data ifrån länkade tabeller i en relationsdatabas efter önskemål,
så kan inte jag komma på någon annan lösning än denna (nedanför i kod-block) för att åstakomma det jag vill.

Skall man istället sammanställa alla sökdata så att det ligger i dubbla tabeller för att underlätta söknigen,
eller skall man skapa temporära tabeller?

Tacksam för en liten redogörelse av detta fenomen.
(Jag fick nämligen bassning i ett annat (dumt ;) ) forum, där av min fråga.)

    DECLARE @param1 as varchar(150),@sql as varchar(2000),@mycount as int,@c as int
    DECLARE @andor as varchar(3), @curr as varchar(3),@orderby as varchar(20)
    SET @c=0
    SET @andor = 'OR'
    SET @sql = ''
    SET @curr='SEK'
    SET @orderby = '1,2,3,4,5'
    SET @param1 = Replace('Detta är ett test',' ','.')
    SET @mycount = (select len(@param1) - len(replace(@param1,'.','')))

    WHILE @c <= @mycount
 
        BEGIN
            SET @sql = @sql + 
             '(s.keywords LIKE ''%'+ PARSENAME(@param1, @c+1) +'%'' OR 
             s.city LIKE ''%'+ PARSENAME(@param1, @c+1) +'%'' OR 
             s.province LIKE ''%'+ PARSENAME(@param1, @c+1) +'%'' OR 
             c.cKeywords LIKE ''%'+ PARSENAME(@param1, @c+1) +'%'') '+ @andor +' '
            SET @c=@c+1
        END
    
SET @sql = left(@sql,len(@sql)-3)

SET @sql = 'SELECT s.id,min(sp.picid),s.province,s.city,
    s.bedsh,s.bedr,s.bathr,s.area,s.dish,s.wash,s.air,
    s.ppool,s.smook,c.cNameEN, 
    min(p.pricew)*r.rate, 
    max(p.pricew)*r.rate,s.advid 
    FROM search1 AS s 
    LEFT JOIN search_pics as sp ON s.id=sp.shid 
    INNER JOIN countries AS c ON s.country=c.id 
    INNER JOIN pricecategory as p ON s.id=p.shid 
    INNER JOIN ratesnew as r ON r.currencyF=p.currency 
    WHERE r.currencyT='''+ @curr +''' AND s.bedsl>=0 AND s.bedsh<=9999 AND ('+ @sql +') 
    GROUP BY s.id,s.province,s.city,s.bedsh,s.bedr,s.bathr,s.area,
    s.dish,s.wash,s.air,s.ppool,s.smook,c.cNameEN,r.rate,s.advid  
    ORDER BY '+ @orderby

exec(@sql)
tohaMedlem sedan dec. 1999698 inlägg
#2

Det är klurigt. Jag skulle inte genererat sql-kod mha en SP, det är så dålig stränghantering där. Hellre med C# eller ASP eller dyl.

Undra om jag inte skulle lägga in alla ord som jag vill matcha (dom i param1) i en @table variabel och gjort en INNER JOIN med LIKE i ON-delen:

...
FROM
search1 AS s
INNER JOIN
@myTable t
ON
s.keywords LIKE '%' + t.word + '%'
OR
s.city LIKE '%' + t.word + '%'
OR
s.province LIKE '%' + t.word + '%'

Vilket skulle funka bra om man vill att det ska vara OR för alla ord i @param1. Man kanske kan returnera antal ordträffar i @myTable och matcha med antal ord i @param1 på något sätt?

tohaMedlem sedan dec. 1999698 inlägg
#3

Jag har en user function som tar en CSV-sträng och lägger in värdena i en table variabel som jag brukar använda mig av:

SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS OFF 
GO

ALTER     FUNCTION parseString
(
	@sIds	AS VARCHAR(8000)
)
RETURNS @Ret TABLE(IDs INT)
AS
BEGIN

	DECLARE @FirstPos	INT
	DECLARE @FirstPos1	INT
	DECLARE @SecondPos	INT
	
	IF ( datalength( @sIds ) > 0 )
	BEGIN
		SET @FirstPos = 1
		
		SELECT @SecondPos = charindex(',', @sIds, @FirstPos)
		
		WHILE ( @SecondPos > 0 )
		BEGIN
			INSERT INTO @Ret
			VALUES( cast( substring( @sIds, @FirstPos, @SecondPos - @FirstPos ) AS INT) )
		
			SET @FirstPos = @SecondPos + 1
			SET @SecondPos = charindex( ',', @sIds, @FirstPos )
		END

		INSERT INTO @Ret
		VALUES( cast( right( @sIds, datalength( @sIds ) - @FirstPos + 1 ) AS INT ) )
	END

	RETURN
END

GO
SET QUOTED_IDENTIFIER OFF 
GO
SET ANSI_NULLS ON 
GO

Blir alltså en tabell med en kolumn, "IDs".

tohaMedlem sedan dec. 1999698 inlägg
#4

Har funderat på om man skapar en "Full text index" på en tabell och kör uttryck mot det. Då kan man använda sig av "CONTAINS()" och "FREETEXT()", som jag aldrig har testat men då kan man köra uttryck som:

USE Northwind
SELECT CategoryName
FROM Categories
WHERE CONTAINS(Description, '"sea*" OR "bread*"')
GO

USE Northwind
GO
SELECT CategoryName, Description
FROM Categories
WHERE CONTAINS(Description, 'ISABOUT (spread weight (.8), 
   sauces weight (.4), relishes weight (.2) )' )
GO

Jag vet dock inte om man kan skicka in själva uttryckssträngen i form av en parameter till en SP. Det ska även gå att "vikta" orden så att vissa ord är värda mer i resultatet (som i ex ovan). Men jag har aldrig testat det här så jag vet inte exakt vilka begränsningarna är. Sry.

Jesper TMedlem sedan nov. 20017 058 inlägg
#5

Toha detta är guld värt.
Jag hade också tänkt mig att testa att full-text-indexera de kolumnerna som sökningen skall gå igenom men jag är helt newbe där så det får vänta lite.
Kommer titta på det så småning om och återkomma.

Tack!

Genererad på 376 ms · cache AV · v20260730165559-full.f96bc7eb