Как эффективно объединить записи с отдельной строкой таблицы - PullRequest
1 голос
/ 05 ноября 2010

У меня большая таблица с множеством повторяющихся строковых данных. Чтобы сэкономить место, я переместил строковые данные в отдельную таблицу. Мои таблицы теперь выглядят примерно так:

MyRecords
RecordId (int) | FieldA (int) | FieldB (datetime) | FieldC (...) | MyString1Id (int) | MyString2Id (int) | MyString3Id (int) | ...

MyStrings
StringId (int) | StringValue (varchar)

Таблица MyRecords имеет около 10 внешних ключей для таблицы строк. У меня есть хранимая процедура GetMyRecords, которая извлекает список записей с фактическими строковыми значениями. Этот sp теперь имеет 10 соединений с таблицей строк для каждого отношения строки:

SELECT [Field1], [Field2], [Field3], ..., [Strings1].[StringValue], [Strings2].[StringValue], ...
 FROM MyRecords INNER JOIN
   MyStrings AS Strings1 ON MyRecords.MyString1Id = Strings1.StringId INNER JOIN
   MyStrings AS Strings2 ON MyRecords.MyString2Id = Strings2.StringId INNER JOIN
   MyStrings AS Strings3 ON MyRecords.MyString3Id = Strings3.StringId INNER JOIN
            (more joins)
    WHERE [Field1] = @Field1 AND [Field2] = @Field2

GetMyRecords значительно медленнее, чем я хотел бы из-за всех соединений. Как я мог улучшить производительность для этого зр? Можно ли как-нибудь превратить это в одно соединение?

Таблица строк имеет кластеризованный первичный ключ на StringId, и все поля where находятся в некластеризованном индексе на таблице MyRecords.

Ответы [ 3 ]

4 голосов
/ 05 ноября 2010

Возможно, вам следует сделать еще один шаг к нормализации и создать таблицу соединений. Вместо столбцов MyStringNId в MyRecords есть третья таблица:

CREATE TABLE RecordsStrings (
    RecordId [theDataType] NOT NULL REFERENCES MyRecords (RecordId),
    StringId [theDataType] NOT NULL REFERENCES MyStrings (StringId)
)

Тогда не удобно иметь все строки в одной и той же строке возвращаемых данных из SELECT (хотя, может быть, есть способ сделать это с помощью сводной таблицы), поэтому, вероятно, лучше реструктурировать вызывающий код иметь дело с результатами, возвращенными из:

SELECT [StringValue]
FROM   [MyStrings] s
INNER JOIN [RecordsStrings] rs ON rs.StringId = s.StringId
INNER JOIN [MyRecords] r ON rs.RecordId = r.RecordId
WHERE  r.Field1 = @Field1 AND r.Field2 = @Field2

Если вам нужны другие поля из MyRecords, вы также можете выбрать их, хотя они будут отображаться в каждой соответствующей строке. Однако, если у вас есть несколько совпадений в Field1 и Field2, это может быть полезно.

2 голосов
/ 05 ноября 2010

Могу ли я как-то превратить это в одно соединение?

Если для одной и той же комбинации строк характерно несколько строк MyRecordsтогда имеет смысл хранить эти комбинации в отдельной таблице.Тогда вы можете выполнить одно соединение.

Пока вы храните только отдельные строки, это невозможно сделать в одном соединении, так как нужно искать каждую строку отдельно.

Вы можете упростить чтение и запись запросов, создав представление таблицы, включающее все объединения.Это не улучшит производительность, но заставит ваши запросы выглядеть намного лучше.

Как я могу улучшить производительность для этого sp?

Есть вещи, которые вы можете сделать, в зависимости от формы данных.

Если строки в одном поле содержат (в основном) информацию, отличную от другой, то вы можете попробовать поместить их в разные таблицы.Существует вероятность, что это может улучшить производительность, если максимальная длина одного поля намного меньше другого или если число различных значений для одного поля намного меньше другого.

1 голос
/ 05 ноября 2010

Первым шагом было бы провести анализ производительности, чтобы увидеть, где проблемы.

Хотя бы просто, вы можете немного повысить производительность, используя (nolock) для объединенных таблиц.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...