лучший оптимизированный способ со строго типизированными полями, это сделать так:
CREATE TABLE Persons
(PersonID int identity(1,1) primary key
,Firstname varchar(...)
,Lastname varchar(...)
,Email varchar(...)
,Phone varchar(...)
,....
)
тогда наиболее оптимизированный запрос будет:
SELECT
PersonID,Firstname,Lastname,Email,Phone
FROM Persons
WHERE ...
Добавьте все основные столбцы в таблицу персон. если вам нужно специализироваться, создайте дополнительные таблицы:
--one person can play many instruments with this table
CREATE TABLE PersonMusicians
(PersonID int --pk fk to Persons.PersonID
,InstrumentCode char(1) --pk
,...
)
--only one row per person with this table
CREATE TABLE PersonTeachers
(PersonID int --pk fk to Persons.PersonID
,FavoriteSubjectCode char(1)
,SchoolName varchar(...)
)
если вам нужно иметь неограниченное количество полей динамических атрибутов, то я бы создал вышеуказанную структуру как можно более полно (как можно больше общих полей), а затем создал бы таблицу «AdditionalInfo», в которой хранится вся информация, например:
AdditionalInfoFields
FieldID int identity(1,1) primary key
FieldName varchar(...)
AdditionalInfo
AdditionalInfoID int identity(1,1) primary key
PersonID int fk to Persons.PersonID
FieldID int fk to AdditionalInfoFields.FieldID
FieldValue varchar(..) or you can look into sql_variant
У
есть индекс на AdditionalInfo.PersonID+FieldID
, и если вы будете искать всех людей, имеющих атрибут X, тогда есть и другой, такой как AdditionalInfo.FieldID+PersonID
Если не считать ничего из вышеперечисленного, вам нужно будет использовать четыре левых внешних соединения, как вы упомянули в своем варианте №1:
SELECT
P.ID, p.Name
, p1.Value AS Firstname
, p2.value AS Lastname
, p3.Value AS Email
, p4.Value AS Phone
FROM Persons p
LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Firstname'
LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Lastname'
LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Email'
LEFT OUTER JOIN Profile p1 ON p.PersonID=p1.PersonID AND p1.FieldName='Phone'
WHERE ....
Вы всегда можете создать материализованное представление с индексом из этого 4-го левого запроса соединения и иметь для вас данные, рассчитанные заранее, что должно ускорить его.