sql >> Databasteknik >  >> RDS >> Mysql

hur implementerar man sökning efter 2 olika tabelldata?

Här är några "spelregler" som du måste tänka på för att lösa detta problem. Du känner säkert till dessa redan, men om du anger dem tydligt kan det hjälpa andra läsare att bekräfta.

  • Alla index i MySQL kan endast referera till kolumner i en enda bastabell. Du kan inte skapa ett fulltextindex som indexerar över flera tabeller.
  • Du kan inte definiera index för vyer, bara bastabeller.
  • En MATCH() fråga mot ett fulltextindex måste matcha mot alla kolumner i fulltextindexet, i den ordning som anges i indexet.

Jag skulle skapa en tredje tabell för att lagra innehållet du vill indexera. Inget behov av att lagra detta innehåll redundant - lagra det endast i den tredje tabellen. Detta lånar ett koncept av en "vanlig superklass" från objektorienterad design (i den mån vi kan tillämpa det på RDBMS-design).

CREATE TABLE Searchable (
  `id` SERIAL PRIMARY KEY,
  `title` varchar(100) default NULL,
  `description` text,
  `keywords` text,
  `url` varchar(255) default '',
  FULLTEXT KEY `TitleDescFullText` (`keywords`,`title`,`description`,`url`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `shopitems` (
  `id` INT UNSIGNED NOT NULL,
  `ShopID` INT UNSIGNED NOT NULL,
  `ImageID` INT UNSIGNED NOT NULL,
  `pricing` varchar(45) NOT NULL,
  `datetime_created` datetime NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

CREATE TABLE `shops` (
  `id` INT UNSIGNED NOT NULL,
  `owner_id` varchar(255) default NULL,
  `datetime_created` datetime default NULL,
  `created_by` varchar(255) default NULL,
  `datetime_modified` datetime default NULL,
  `modified_by` varchar(255) default NULL,
  `overall_rating_avg` decimal(4,2) default '0.00',
  PRIMARY KEY (`id`),
  FOREIGN KEY (`id`) REFERENCES Searchable (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Observera att den enda tabellen med en nyckel för automatisk ökning nu är Searchable . Tabellerna shops och shopitems använd en nyckel med en kompatibel datatyp, men inte automatisk ökning. Så du måste skapa en rad i Searchable för att generera id värde, innan du kan skapa motsvarande rad i någon av shops eller shopitems .

Jag har lagt till FOREIGN KEY deklarationer i illustrationssyfte, även om MyISAM tyst ignorerar dessa begränsningar (och du vet redan att du måste använda MyISAM för att ha stöd för fulltextindexering).

Nu kan du söka efter textinnehållet i båda shops och shopitems i en enda fråga, med ett enda fulltextindex:

SELECT S.*, sh.*, si.*,
  MATCH(keywords, title, description, url) AGAINST('dummy') As score
FROM Searchable S
LEFT OUTER JOIN shops sh ON (S.id = sh.id)
LEFT OUTER JOIN shopitems si ON (S.id = si.id)
WHERE MATCH(keywords, title, description, url) AGAINST('dummy')
ORDER BY score DESC;

Naturligtvis för en given rad i Searchable endast en tabell ska matcha, antingen butiker eller butiksartiklar, och dessa tabeller har olika kolumner. Så antingen sh.* eller si.* blir NULL i resultatet. Det är upp till dig att formatera utdata i din applikation.

Ett par andra svar har föreslagit att du använder Sphinx Search . Detta är en annan teknik som kompletterar MySQL och lägger till mer sofistikerad fulltextsökningsfunktion. Den har bra prestanda för frågor, så vissa människor har blivit ganska förtrollade av den.

Men att skapa index och särskilt lägga till ett index stegvis är dyrt. Faktum är att det är så kostsamt att uppdatera ett Sphinx Search-index att den rekommenderade lösningen är att skapa ett index för äldre, arkiverade data och ett annat mindre index för senaste data som är mer sannolikt att uppdateras. Sedan måste varje sökning köra två frågor, mot de två separata indexen. Och om din data inte naturligt lämpar sig för att mönstret med äldre data är oföränderligt, kanske du inte kan dra nytta av det här tricket ändå.

Angående din kommentar:Här är ett utdrag ur Sphinx Search-dokumentationen om liveuppdateringar av ett index:

Tanken är att eftersom det är kostsamt att uppdatera ett Sphinx Search-index är deras lösning att göra indexet du uppdaterar så litet som möjligt. Så att endast de senaste foruminläggen (i deras exempel), medan den större historiken för arkiverade foruminlägg aldrig ändras, så du bygger ett andra, större index för den samlingen en gång. Om du vill göra en sökning måste du naturligtvis fråga båda indexen.

Med jämna mellanrum, säg en gång i veckan, kommer de "senaste" forummeddelandena att betraktas som "arkiverade" och du måste slå samman det aktuella indexet för de senaste inläggen till det arkiverade indexet och starta om det mindre indexet. De påpekar att det är mer effektivt att slå samman två Sphinx Search-index än att återindexera efter en uppdatering av data.

Men min poäng är att inte varje datauppsättning naturligt faller in i mönstret att ha en arkiverad datauppsättning som aldrig ändras, jämfört med nya data som uppdateras ofta.

Ta din databas till exempel:Du har butiker och butiksartiklar. Hur kan du dela upp dessa i rader som aldrig ändras, kontra nya rader? Alla butiker eller produkter i katalogen bör tillåtas uppdatera sin beskrivning. Men eftersom det skulle kräva att du måste bygga om hela Sphinx Search-indexet varje gång du gör en ändring, blir det en mycket dyr operation. Kanske skulle du ställa ändringar i kö och tillämpa dem i en batch och bygga om indexet en gång i veckan. Men försök förklara för butiksförsäljarna varför en mindre ändring av deras butiksbeskrivning inte träder i kraft förrän på söndag kväll.



  1. Hur infogar man specialtecken i en databas?

  2. Döda en postgresql-session/anslutning

  3. Innebär en Postgres UNIQUE begränsning ett index?

  4. Konvertera 'datetime' till 'datetimeoffset' i SQL Server (T-SQL-exempel)