Как вы можете создавать кластерные индексы с помощью Fluent NHibernate? - PullRequest
3 голосов
/ 31 августа 2009

Я использую Fluent-NHibernate (с автоматическим отображением) для генерации моих таблиц, но хотел бы выбрать другой кластеризованный индекс, чем поле идентификатора, которое используется по умолчанию. Как создать кластеризованные индексы с помощью Fluent NHibernate для поля, отличного от поля первичного ключа по умолчанию?

Основная причина этого проста. Я использую Guids для моих полей первичного ключа. По умолчанию NHibernate создает кластерные индексы в полях первичного ключа. Поскольку направляющие обычно не являются последовательными, кластеризация в поле первичного ключа вызывает проблемы с производительностью.

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

Чтобы минимизировать это, у меня есть столбец с именем CreatedOn, который имеет тип DateTime. Мне нужно, чтобы таблица была кластеризована в этом столбце CreatedOn, чтобы все новые записи добавлялись, а не вставлялись.

Любые идеи о том, как этого добиться, приветствуются !!!

Примечание: я понимаю, что могу использовать последовательные направляющие, но предпочитаю не идти по этому пути из соображений безопасности.


Примечание: у меня до сих пор нет ответа на этот пост, но у меня есть несколько идей, над которыми я сейчас размышляю.

  1. Используя NHibernate без Fluent, я думаю, что возможно создать кластерные индексы непосредственно в NHibernate. Я еще недостаточно знаю о NHibernate, чтобы знать, как это сделать. Я просто довольно (как в почти абсолютно) уверен, что это может быть сделано.

  2. Fluent-NHibernate используется для включения способа установки атрибутов (например, кластеризованного индекса) в объекте SQL перед последним переписыванием. Теперь эта опция, кажется, исчезла. Я, вероятно, опубликую вопрос где-нибудь, чтобы увидеть, доступна ли эта опция. Если это так, я мог бы использовать это для установки кластеризованного индекса.

  3. Fluent-NHibernate предоставляет возможность выставить конфигурацию для ручного редактирования, как только она будет свободно создана. Я не пробовал эту функцию, но ожидаю, что она может предложить уровень детализации, необходимый для установки кластеризованных индексов.

  4. В худшем случае я могу написать сценарий SQL для изменения кластеризованных индексов на всех моих таблицах после их создания. Однако у меня есть пара вопросов относительно этого подхода. О. Поскольку я использую автоматическую генерацию схемы, будет ли NHibernate "отменять" мой кластерный индекс, когда он будет в следующий раз оценивать конфигурацию? 2. Будет ли ошибка NHibernate, если он обнаружит, что кластерный индекс был изменен? Я должен проверить это, но пока не сделал этого. Я действительно ненавижу это решение, хотя. Я тестирую свою БД против SQLServer2008 и MySQL. Частью красоты NHibernate является то, что он не зависит от базы данных. Как только мы представим сценарии, все ставки отменены.

  5. Существует интерфейс, который используется в свободно распространяемых соглашениях, который называется IPropertyInstance. Классы, которые наследуются от этого интерфейса, имеют свойство Index, которое позволяет создавать индекс в поле. Проблема заключается в том, что нет флага или другого параметра, позволяющего создать индекс как кластеризованный. Простейшим решением было бы добавить свойство к этому методу, чтобы можно было создавать кластерные индексы. Я думаю, что могу предложить это разработчикам Fluent-NHibernate.

Ответы [ 4 ]

7 голосов
/ 14 января 2011

Это старый пост, но я надеюсь, что может помочь кому-то еще. Это происходит из моего опыта на MS SQL Server. Я считаю, что разные платформы требуют разных решений, но это должно стать хорошей отправной точкой.

NHibernate не устанавливает индекс CLUSTERED для первичного ключа. Это поведение SQL Server по умолчанию. Поскольку в таблице может быть только один CLUSTERED, нам нужно сначала избежать создания CLUSTERED для первичного ключа.

Единственный способ сделать это - создать собственный диалект, переопределяющий свойство PrimaryKeyString. Значение по умолчанию NHibernate взято из Dialect.cs :

    public virtual string PrimaryKeyString
    {
        get { return "primary key"; }
    }

Для SQL Server

    public override string PrimaryKeyString
    {
        get { return "primary key nonclustered"; }
    }

Это заставит SQL Server создать НЕКЛАСТЕРНЫЙ первичный ключ. Теперь вы можете добавить свой собственный индекс CLUSTERED в ваш любимый столбец с помощью тега в файле отображения XML.

<database-object>
  <create>
    create clustered index IX_CustomClusteredIndexName on TableName (ColumnName ASC)
  </create>
  <drop>
    drop index IX_CustomClusteredIndexName ON TableName
  </drop>
</database-object>
1 голос
/ 01 сентября 2009

Как вы сказали сами, другой вариант - перейти к стратегии генерации идентификаторов guid.comb, в которой идентификаторы PK основаны на части, которая представляет собой Guid, и части, которая обеспечивает сгенерированные идентификаторы.

Проверьте больше информации в посте Джеффри Палермо здесь .

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

1 голос
/ 31 августа 2009

Я не могу ответить конкретно, но я дам вам некоторую информацию о базе данных, так как я здесь.

Вам необходимо указать NHibernate, чтобы он создавал первичный ключ по некластерному индексу. В таблице может быть только кластеризованный индекс, поэтому необходимо создать таблицу в виде кучи, а затем поместить в нее кластеризованный индекс.

0 голосов
/ 13 июня 2012

Так же, как сказал @ abx78, это старый пост, но я также хотел бы поделиться своим знанием решения этой проблемы. Я построил решение для идеи 3 «Свободное отображение NHibernate»:

После того, как конфигурация была собрана (таким образом, сопоставления проанализированы), Fluent NHibernate дает нам возможность изучить фактические сопоставления с помощью configuration.ClassMappings и configuration.CollectionMappings. Последний используется в приведенном ниже примере для установки составного первичного ключа, в результате чего в Sql Server создается кластеризованный индекс (как указывает @ abx78):

foreach (var collectionMapping in configuration.CollectionMappings) {
    // Fetch the columns (in this example: build the columns in a hacky way)
    const string columnFormat = "{0}_id";
    var leftColumn = new Column(string.Format(
        columnFormat,
        collectionMapping.Owner.MappedClass.Name));
    var rightColumn = new Column(string.Format(
        columnFormat,
        collectionMapping.GenericArguments[0].Name));
    // Fetch the actual table of the many-to-many collection
    var manyToManyTable = collectionMapping.CollectionTable;
    // Shorten the name just like NHibernate does
    var shortTableName = (manyToManyTable.Name.Length <= 8)
                                ? manyToManyTable.Name
                                : manyToManyTable.Name.Substring(0, 8);
    // Create the primary key and add the columns
    // >> This part could be changed to a UniqueKey or to an Index
    var primaryKey = new PrimaryKey {
        Name = string.Format("PK_{0}", shortTableName),
    };
    primaryKey.AddColumn(leftColumn);
    primaryKey.AddColumn(rightColumn);
    // Set the primary key to the junction table
    manyToManyTable.PrimaryKey = primaryKey;
    // <<
}

Источник: Свободный NHibernate: Как создать кластеризованный индекс в таблице соединений «многие ко многим»?

...