【问题标题】:Getting Hibernate to generate indexes on foreign keys让 Hibernate 在外键上生成索引
【发布时间】:2010-06-03 22:17:47
【问题描述】:

我在一个相当大的项目中使用 Hibernate 3.3.2,使用 PostgreSQLDialect 使用 PostgreSQL 8.4。

按照我们建立关系的方式,我们最终会对表的外键属性进行大量搜索。

出于性能原因,当我们使用 hbm2dll.auto 创建表时,我希望 Hibernate 将索引添加到所有外键列。

MySQL 会自动为这些列添加索引,但在 Postgres 中似乎没有办法做到这一点。

是否有我可以在某处设置的选项,或者我可以添加到我的 hbm.xml 文件中以实现这一点?

【问题讨论】:

    标签: hibernate postgresql indexing foreign-keys


    【解决方案1】:

    这是一个快速而粗略的查询,它将为架构中每个已定义外键的索引生成 DDL:

    SELECT 'CREATE INDEX fk_' || conname || '_idx ON ' 
           || relname || ' ' || 
           regexp_replace(
               regexp_replace(pg_get_constraintdef(pg_constraint.oid, true), 
               ' REFERENCES.*$','',''), 'FOREIGN KEY ','','') || ';'
    FROM pg_constraint 
    JOIN pg_class 
        ON (conrelid = pg_class.oid)
    JOIN pg_namespace
        ON (relnamespace = pg_namespace.oid)
    WHERE contype = 'f'
      AND nspname = 'public';
    

    这仅在 PostgreSQL 8.4 中测试过,但我认为它应该适用于大多数 8.x 版本。

    另请注意,这不会检测到哪些已被索引覆盖,因此您可能会有一些重复。

    【讨论】:

    • 一旦建立了数据库,这很有帮助,但是对于这个问题,我真的更感兴趣的是让 hibernate 在创建表时为我做这件事。不过,对于我的其他相关问题,这是一个很好的答案:stackoverflow.com/questions/2970050/…
    • 我认为,它不适用于引用的命名变量。
    • @Ravshan:暂时忽略不应在数据库表定义中使用带引号的名称,这在 9.3 中似乎对我有用:select distinct regexp_replace(regexp_replace(pg_get_constraintdef(oid), '^ .*REFERENCES', 'CREATE INDEX ON'), ').*$', ');') 来自 pg_constraint where contype = 'f'。
    • 有时使用带引号的标识符是不可避免的(至少出于遗留目的)。
    【解决方案2】:

    Hibernate 只对 MySQL 强制创建索引,而不是对 PostgreSQL、Oracle 等。MySQL 不允许没有索引的外键,其他数据库没有这个限制。

    Sybase 有一个explanation,为什么不强制执行索引是一件好事,Hibernate forum 也有一个关于它的主题(与 Oracle 相关),包括一种解决方法。但在开始创建大量索引之前,请先检查是否需要所有这些索引。在许多情况下,索引可以与其他索引组合以加快速度。这一切都取决于!

    对查询使用 EXPLAIN 以查看数据库如何执行它们、使用了哪些索引、缺少索引的位置等。

    【讨论】:

    • 最好不要强制外键有索引,但它似乎是一个不错的选择。
    【解决方案3】:

    尝试以下任何一种:

    <many-to-one name="master" class="Master" column="master_id" index="my_index_name" />
    
    <many-to-one name="master" class="Master">
        <column name="master_id" index="my_index_name" />
    </many-to-one>
    

    【讨论】:

    • 我尝试了这两种方法,但是在数据库中搜索应该创建的索引没有结果=\不确定我可能做错了什么,但会继续插入。
    • 你用什么设置?也许它们不是用“update”添加的,而是用“create”或“create-drop”添加的?另一种思路,会不会是这样的bug:opensource.atlassian.com/projects/hibernate/browse/HHH-1012
    【解决方案4】:

    除了马修的回答: 添加

    AND NOT EXISTS (
      SELECT * FROM pg_class pgc
        JOIN pg_namespace pgn ON (pgc.relnamespace = pgn.oid)
      WHERE relkind='i'
        AND pgc.relname = ('fk_' || conname || '_idx') )
    

    在分号之前只创建不存在的索引。这允许您重复执行语句而不会产生“relation fk_...”已经存在”错误。

    【讨论】:

      猜你喜欢
      • 2011-01-31
      • 2016-03-21
      • 1970-01-01
      • 2011-03-29
      • 2017-08-05
      • 2016-08-14
      • 2011-12-05
      • 2013-05-10
      • 1970-01-01
      相关资源
      最近更新 更多