Преди да преминем към преждевременна оптимизация режим, може да е полезно да разгледате следния шаблон на заявка. Ако не друго, това може да се използва като базова линия, спрямо която може да се измери ефективността на възможните оптимизации.
SELECT T.Tagid, TagInfo.TagName, COUNT(*)
FROM Items I
JOIN Tags TagInfo ON TagInfo.TagId = T.TagId
JOIN ItemTagMap T ON I.ItemId = T.ItemId
--JOIN ItemTagMap T1 ON I.ItemId = T1.ItemId
WHERE I.ItemId IN
(
SELECT ItemId
FROM Items
WHERE -- Some typical initial search criteria
Title LIKE 'Bug Report%' -- Or some fulltext filter instead...
AND ItemDate > '02/22/2008'
AND Status = 'C'
)
--AND T1.TagId = 'MySql'
GROUP BY T.TagId, TagInfo.TagName
ORDER BY COUNT(*) DESC
Подзаявката е "движещата заявка", т.е. тази, която съответства на първоначалните критерии на крайния потребител. (вижте по-долу за подробности как тази заявка, изисквана няколко пъти, може да се побере в цялостен оптимизиран поток) Коментира се JOIN на T1 (и евентуално T2, T3, когато са избрани няколко маркера) и, с клаузата WHERE, свързаният критерии. Те са необходими, когато потребителят избере конкретен маркер, независимо дали като част от първоначалното търсене или чрез прецизиране. (Може да е по-ефективно да поставите тези съединения и клаузи where в подзаявката; повече за тях по-долу)
Дискусия... „Заявката за шофиране“ или нейна вариация е необходима за две различни цели:
-
1, за да предоставите пълния списък с ItemId, който е необходим за изброяване на всички свързани тагове.
-
2 за предоставяне на първите N стойности на ItemId (N е размерът на показваната страница) с цел търсене на подробна информация за артикула в таблицата с артикули.
Имайте предвид, че пълният списък не трябва да бъде сортиран (или може да се възползва от сортиране в различен ред), при което вторият списък трябва да бъде сортиран въз основа на избора на потребителя (да речем по дата, низходящ или по заглавие, по азбучен ред ). Също така имайте предвид, че ако се изисква някакъв ред на сортиране, цената на заявката ще означава работа с пълния списък (срамувайки се от странна оптимизация от самия SQL и/или някаква денормализация, SQL трябва да "вижда" последните записи в този списък , в случай че принадлежат към върха, сортирано).
Последният факт е в полза на наличието на една и съща заявка и за двете цели, съответният списък може да се съхранява във временна таблица. Общият поток би бил бързо да се търсят най-добрите записи на N артикули с техните подробности и да се връщат веднага в приложението. След това приложението може да получи ajax-fashion списъка с етикети за усъвършенстване. Този списък ще бъде произведен със заявка, подобна на тази по-горе, където подзаявката се заменя с „select * from temporaryTable“. Шансовете са добри SQL оптимизаторът да реши да сортира този списък (в някои случаи), нека го оставим да го направи, вместо да го отгатва и сортира изрично.
Друга точка, която трябва да вземете предвид, е може би да внесете присъединяването(ята) в таблицата ItemTagMap вътре в "заявката за управление", а не както е показано по-горе. Вероятно е най-добре да го направите, както за производителност, така и защото ще създаде правилния списък за цел №2 (показване на страница с елементи).
Заявката/потокът, описан по-горе, вероятно ще се мащабира доста добре, дори при сравнително скромен хардуер; ориентировъчно в 1/2 милион+ артикули, с продължителни потребителски търсения може би до 10 в секунда. Един от ключовите фактори би бил селективността на първоначалните критерии за търсене.
Идеи за оптимизация
- [В зависимост от типичните случаи на търсене и от статистиката на данните] може да има смисъл да се денормализира чрез пренасяне (всъщност дублиране) на някои от полетата на Items в таблицата ItemTagMap. По-специално кратките полета могат да бъдат „добре дошли“ там.
- Тъй като данните нарастват в милиони+ елемента, бихме могли да използваме типично силната корелация на някои тагове (напр. в SO, PHP често идва с MySql, между другото често без основателна причина...), с различни трикове. Например въвеждането на „multi-Tag“ TagIds може да направи логиката на въвеждане малко по-сложна, но също така може да намали значително размера на картата.
-- 'не казах нищо! --
Трябва да бъдат избрани подходяща архитектура и оптимизации в светлината на действителните изисквания и на ефективния статистически профил на данните...