sql >> Databáze >  >> RDS >> Mysql

jak implementovat vyhledávání 2 různých dat tabulky?

Zde je několik "pravidel hry", která musíte mít na paměti, abyste tento problém vyřešili. Pravděpodobně je již znáte, ale jejich jasné uvedení může pomoci potvrdit ostatním čtenářům.

  • Všechny indexy v MySQL mohou odkazovat pouze na sloupce v jedné základní tabulce. Nemůžete vytvořit fulltextový index, který indexuje přes více tabulek.
  • Nelze definovat indexy pro zobrazení, pouze základní tabulky.
  • A MATCH() dotaz na fulltextový index se musí shodovat se všemi sloupci ve fulltextovém indexu v pořadí deklarovaném v indexu.

Vytvořil bych třetí tabulku pro uložení obsahu, který chcete indexovat. Není třeba tento obsah ukládat nadbytečně – uložte jej pouze do třetí tabulky. To si vypůjčuje koncept „společné supertřídy“ z objektově orientovaného designu (pokud jej můžeme aplikovat na návrh RDBMS).

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;

Všimněte si, že jediná tabulka s klíčem automatického přírůstku je nyní Searchable . Tabulky shops a shopitems použijte klíč s kompatibilním datovým typem, ale ne automatické zvýšení. Takže musíte vytvořit řádek v Searchable vygenerovat id hodnotu, než budete moci vytvořit odpovídající řádek v obou shops nebo shopitems .

Přidal jsem FOREIGN KEY deklarace pro ilustrační účely, i když MyISAM bude tato omezení tiše ignorovat (a vy už víte, že musíte použít MyISAM, abyste měli podporu pro fulltextové indexování).

Nyní můžete prohledávat textový obsah obou shops a shopitems v jediném dotazu pomocí jediného fulltextového indexu:

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;

Samozřejmě pro daný řádek v Searchable měla by odpovídat pouze jedna tabulka, ať už obchody nebo položky obchodu, a tyto tabulky mají různé sloupce. Takže buď sh.* nebo si.* bude ve výsledku NULL. Je jen na vás, jak zformátujete výstup ve vaší aplikaci.

Několik dalších odpovědí navrhlo použít Sphinx Search . Jedná se o další technologii, která doplňuje MySQL a přidává sofistikovanější možnost fulltextového vyhledávání. Má skvělý výkon pro dotazy, takže někteří lidé s ním byli docela okouzleni.

Ale vytváření indexů a zejména postupné přidávání do indexu je nákladné. Aktualizace indexu Sphinx Search je ve skutečnosti tak nákladná, že doporučeným řešením je vytvořit jeden index pro starší archivovaná data a další menší index pro nedávná data, u kterých je pravděpodobnější, že budou aktualizována. Každé vyhledávání pak musí spustit dva dotazy proti dvěma samostatným indexům. A pokud se vaše data přirozeně nehodí k tomu, že se starší data nemění, pak možná nebudete moci tento trik stejně využít.

K vašemu komentáři:Zde je výňatek z dokumentace Sphinx Search o živých aktualizacích indexu:

Myšlenka je taková, že protože je nákladné aktualizovat index Sphinx Search, jejich řešením je udělat index, který aktualizujete, co nejmenší. Takže pouze nejnovější příspěvky na fóru (v jejich příkladu), zatímco větší historie archivovaných příspěvků na fóru se nikdy nemění, takže pro tuto sbírku vytvoříte druhý, větší index jednou. Samozřejmě, pokud chcete provést vyhledávání, musíte se dotazovat na oba indexy.

Pravidelně, řekněme jednou týdně, by se „nedávné“ zprávy na fóru považovaly za „archivované“ a vy byste museli sloučit aktuální index pro poslední příspěvky do archivovaného indexu a spustit menší index znovu. Upozorňují na to, že sloučení dvou indexů Sphinx Search je efektivnější než reindexace po aktualizaci dat.

Ale jde mi o to, že ne každý soubor dat přirozeně spadá do vzoru mít archivovaný soubor dat, který se nikdy nemění, oproti nedávným datům, která se často aktualizují.

Vezměte si například svou databázi:Máte obchody a položky. Jak je můžete rozdělit do řádků, které se nikdy nemění, oproti novým řádkům? Jakékoli obchody nebo produkty v katalogu by měly mít možnost aktualizovat svůj popis. Ale protože by to vyžadovalo přebudování celého indexu Sphinx Search pokaždé, když provedete změnu, stává se to velmi nákladnou operací. Možná byste změny seřadili do fronty a aplikovali je v dávce a index jednou týdně znovu sestavili. Ale zkuste vysvětlit prodejcům obchodů, proč se drobná změna v popisu obchodu projeví až v neděli večer.



  1. Sloupec nenalezen:1054 Neznámý laravel sloupce

  2. Připojte se ke vzdálené databázi MySQL z kontejneru dockeru

  3. Tabulky MySql, chyba #1064 &chyba #1068 Definováno více primárních klíčů

  4. Kde podmínka pro spojenou tabulku v Sequelize ORM