Я не понимаю, почему это неэффективное решение.
Это неэффективно, потому что вы должны извлекать и разбивать / искать эту строку для каждого запроса.
Когда вы делаете что-то вроде (как упомянуто в ваших ссылках) Three tables (one for storing all items, one for all tags, and one for the relation between the two)
, тогда вы можете использовать реальную силу реляционной базы данных, индекс .
Вместо того, чтобы разбивать каждую строку натег или набор тегов ... это уже сделано;Вы просто получаете те, которые хотите.Итак, если вы ищете «обувь», то он идет прямо туда (используя индекс, вероятно, log n или быстрее) и возвращает как Nike, так и GAP.Он будет делать это независимо от того, сколько у вас тегов, независимо от того, сколько у вас компаний.
С системой с 3 столами вы выполняете всю тяжелую работу заранее, а затем просто выполняете поиск.
Если вы собираетесь запустить это локально или с ограниченным числом пользователей, ваше решение может подойти.Кодирование также проще.
Как только ваши запросы начнут занимать более нескольких секунд, вы, вероятно, захотите обновить свою систему тегов.Если вы делаете это таким образом, напишите поисковый код отдельно, на случай, если вам нужно его разорвать.
Вопрос из комментария:
Можете ли вы привести примерСистема с 3 столами, нормализованная с атомарностью
Конечно.
Вы в основном просили Третью Нормальную Форму, которая является моей обычной целью.(Я признаю, что часто не делаю 3NF, потому что я оптимизирую; например, сохраняю почтовый индекс с адресами - если вы вне школы, это лучший выбор)
--Sample SQL stackoverflow.com/questions/50793168/database-design-for-tags-or-tagging/50818392
IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = N'ChrisC')
BEGIN
EXEC sys.sp_executesql N'CREATE SCHEMA [ChrisC] AUTHORIZATION [dbo]'
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[ChrisC].[Brands]') AND type in (N'U'))
AND NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[ChrisC].[BrandTags]') AND type in (N'U'))
AND NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[ChrisC].[Tags]') AND type in (N'U'))
BEGIN
CREATE TABLE [ChrisC].[Brands]([pkBrand] [int] IDENTITY(101,1) NOT NULL,[Name] [varchar](40) NULL) ON [PRIMARY]
INSERT INTO [ChrisC].[Brands]([Name])VALUES('Nike'),('GAP')
CREATE TABLE [ChrisC].[BrandTags]([pk] [int] IDENTITY(1,1) NOT NULL,[Brand] [int] NULL,[Tag] [int] NULL) ON [PRIMARY]
INSERT INTO [ChrisC].[BrandTags]([Brand],[Tag])VALUES
(101,201),(101,202),(101,203),(101,204),(101,205),(101,206),(101,207),
(102,208),(102,209),(102,203),(102,207),(102,210)
CREATE TABLE [ChrisC].[Tags]([pkTag] [int] IDENTITY(201,1) NOT NULL,[Tag] [varchar](40) NULL) ON [PRIMARY]
INSERT INTO [ChrisC].[Tags]([Tag])VALUES
('bags'),('football'),('shoes'),('soccer'),('sports'),('track-pants'),('t-shirts'),('jeans'),('perfumes'),('wallets')
SELECT b.[Name], t.Tag
FROM chrisc.Brands b
LEFT JOIN chrisc.BrandTags bt ON pkBrand = Brand
LEFT JOIN chrisc.Tags t ON bt.Tag = t.pkTag
WHERE b.[Name] = 'Nike'
-- Stop execution here to see the tables with data
DROP TABLE [ChrisC].[Brands]
DROP TABLE [ChrisC].[BrandTags]
DROP TABLE [ChrisC].[Tags]
END
IF EXISTS (SELECT * FROM sys.schemas WHERE name = N'ChrisC') DROP SCHEMA [ChrisC]
END