09. januar 2004 - 21:27Der er
34 kommentarer og 1 løsning
hurtige søgninger i mssql
Jeg skal i forbindelse med en asp-aplication bruge nogle hurtige søgninger fra mssql. Databasen ser sådan her ud:
Autonum - int Title - nvarchar 80 Description - nvarchar 200 Meta - nvarchar 250 KeyWords - nvarchar 250 url - nvarchar 250 Lastmodified - smalldatetime
Jeg har prøvet med følgende SELECT, og det kan tage helt op til 60 sec. Har også prøvet at lave en storedProcedure med samme SELECT uden mærkbart resultat.
strSQL = "SELECT top 400 url, title, keywords, LastModified, description, meta, PageRank from "&tabel&" where meta LIKE '% "&strSearchWords&" %'" strSQL = strSQL & " OR description LIKE '% "&strSearchWords&" %'" strSQL = strSQL & " OR title LIKE '% "&strSearchWords&" %'" strSQL = strSQL & " OR keywords LIKE '% "&strSearchWords&" %'"
Cybersikkerhed, realtidsdata og robuste it-systemer er blevet fundamentet for moderne forsvar.
Slettet bruger
09. januar 2004 - 21:34#1
Når du skal søge med like så vil det tage lang tid. Du kan lave et indeks på tabellen for de felter du vil søge på, det skulle gerne optimere søgningen.
Du skal lige være obs på, at brug af OR forhindrer effektiv udnyttelse af indeks, Samtidig er max indeks key length er 900 bytes - du nærmer dig vist den...
En anden ting - du benytter en TOP 400 - det afskærer kun de viste data, men samtlige matchende rækker skal stadig gås igennem. En where betingelse - fx på lastmodified - vil afgrænse resultatsættet og dermed give et hurtigere svar.
Sidst - afhængigt af din server (diske, cpu & ram) er der grænser for hvad sql server kan levere. Sørg for at memory options på sql server og evt andre services er sat så swap undgås - og sørg for at log/data filer ligger på separate fysiske diske eller, bedre, raids.
Arne_v's forslag med en separat tabel vil fungere, den nærmer sig egentlig ideen i et fulltext index - omend den imho vil være hurtigere.
Du skal så lave en "parser" der kan bryde en tekst op i separate ord som du kan indsætte i din leksikontabel og en mange-til-mange der fortæller hvilke ord der bruges i hvilke records i din url/keyword etc tabel. Indsættelsen af nye rækker vil blive sløvet ned, naturligvis, men udsøgning vil blive til et rimelig simpelt sql opslag.
hovsa . En separat tabel på f.eks KeyWords vil give omkring 2 millioner poster. Hvis jeg skal have en søgning på description, title og keywords skal der så søges i 3 tabeller med ca. 9 millioner poster ialt. Derefter skal der sammenlignes med resultater, således at der ikke bliver retuneret dubletter, eller hvad !?!? Vil det stadig være hurtigere ??
Loukas> Indeks er/kan være afsindigt effektive. Den "mindst effektive" form kaldes et binært træ - og i et sådant vil kun 10 opslag afgøre om en bestemt post findes blandt en million poster. Et binært træ har 2 grene på hver niveau.
I MS SQL benyttes bl.a. B+ træer som på hvert niveau har mere end 2 grene, det er altså lavere (færre niveauer) og en smule hurtigere at søge i!
du skal kun have en ord-tabel, andet behøves ikke.
a la ordliste( id (p) ord (ui) ) urltabel( id (p) url metadata keywords title etc etc )
ord2url ( ordid (p) urlid (p) )
select u.* from urltabel u inner join ord2url o2u on u.id = o2u.urlid inner join ordliste o on o2u.ordid = o.id where o.ord in ('hans','peter','lego','osv')
Når en ny række indsættes i "urltabel" skal du altså opdatere ord2url med id værdien for url-en samt id'er for alle de ord der benyttes i recorden.
Søgningen som ovenfor vil så finde alle url-rækker hvor ordlisten indeholder et eller flere af de ord der står i listen. Bemærk at det er enkeltord du søger på. En indtastet søgestreng skal altså brydes op for at søgningen fungerer.
hmm, hvis jeg opretter en ordlisteTabel med ord fra både title og key words kommer der så ikke dubletter ?? Og betyder det noget hvis der gør ? jeg er ikke helt med på idéen med ord2url.
Nej, du indsætter kun et givent ord én gang - det er ligegyldigt i hvilket felt det indgår. Og ja, det betyder noget hvis der gør - men du kan ikke indsætte dubletter når du lægger det angivne unikke indeks på.
ord2url fortæller hvilke ord der er i hvilke url-rækker. Det er en mange-til-mange relation, og den implementeres altid som tabel.
Som du jo grangiveligt er klar over (og har skrevet) er IN det samme som en OR, og en OR respektere ikke indexet, men kan klares vha. en UNION
select * from Table1 where f1 IN('a', 'b', 'c')
Kan omskrives til en meget hurtigere sådan select * from Table1 where f1 = 'a' union select * from Table1 where f1 = 'b' union select * from Table1 where f1 = 'c'
janus_007> En UNION indeholder en implicit distinct, hvorfor du får et resultatsæt der skal sorteres og lægges sammen. Det er en temmelig tung operation.
I stedet for UNION bør man generelt bruge en UNION ALL - den indeholder ikke en DISTINCT og er derfor hurtigere.
Med store datasæt er der aldrig fordel ved at bruge en UNION fremfor en OR - problemet er simpelthen at resultatsættet ikke kan håndteres i ram hvorfor det ryger i TEMPDB i stedet - og dermed taler vi diskhastighed :-(
I de fleste tilfælde vil OR'en give bookmark operationer - dvs gentagne søgninger gennem index - men det er stadig hurtigere end at gennemføre en UNION.
Jeg prøvede lige i en temmelig lille tabel at lave de tre forskellige queryes (en med OR, en med UNION og en med UNION ALL). Query Analyzer har mulighed for at sammenligne cost ved queries vha funktion "Show Execution plan".
Resultat i cost % => OR = 0%, UNION = 52% og UNION ALL = 48%
Ergo - bookmark operationen er billigst (kan ikke måles på skalaen), UNION ALL er billigere end UNION operationen. Havde der ikke været indeks på kolonne jeg brugte i where betingelsen havde resultatet naturligvis været anderledes - men god og korrekt indeksering er altid alfa og omega mht performance.
I øvrigt loukas. Hvordan kan du have 2 millioner keywords? Der er kun omkring 100.000 til 300.000 danske ord (når de mest specielle er med) - og det engelske sprog har ikke meget mere...
trer-> Det var nu også en union all jeg mente, men anyway det ændrer ikke på det faktum at det trick kun virker på mssql6.5 - min fejl :O)
Jeg har nu også lavet en test og den siger at der ingen forskel er på dem. Jeg oprettede en tabel med 1mill rækker, oprettede index på mine sarg's og her sagde execution plan 50% til "or" og 50% til "union all". Jeg kiggede også på io's og det var også det samme: Table 'T_jk'. Scan count 2, logical reads 2087, physical reads 0, read-ahead reads 0.
Eneste jeg lige har herhjemme er en lille MSDE på en singlecpu maskine - og jeg har kun få tabeller og rækker at lege på.
Så: En UNION ALL giver 66% mens en OR giver 34% i cost.
Forskellen er, at jeg får flere bookmark operationer i UNION udtrykket samt en CONCAT mens jeg kun har én bookmark i OR'en. Det er muligvis fordi jeg har et almindeligt non-clustered index på - jeg har ikke prøvet med clustered index.
Anyway: Den korrekte anbefaling er at bruge Show Exec. plan løbende under udviklingen af ens queries - og huske at ens udviklingssetup skal være rimelig tæt på ens prod server hw-mæssigt (antal cpu'er påvirker query planer ret kraftigt).
Professionel Association of SQL Server users. Der er også en dansk afdeling. Jeg skal lige skaffe et link til hjemmesiden - så poster jeg det her. Det bliver senere, skal ud af døren nu.
I Danmark er medlemmerne bl.a. fra Teknologisk Institut, Lego, Danmarks Radio, KMD, Novo Nordisk IT, Miracle, Kbhs Lufthavn, Columbus, Siemens, DM-Data og mange flere...
Det er ikke Access-niveauet det foregår på - men det er rare mennesker :-)
jeg har problemer med dubletter. Jeg har lavet tabellen ved at parse hver enkelt ord fra TITLE og KEYWORDS i tabellen docsDK. Så det skal lige laves om...
OK, nu er jeg med --- selv om det tog lidt tid ;-) Jeg siger tusind tak for hjælpen for nu. Og vender tilbage hvis der kommer flere problemer..
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.