2013-02-22 44 views
0

我正在构建一个游戏,我打算成为一个持久的在线世界(如MMO,但可能不是大量的玩家)。我正在制作游戏地图,只需创建一个2d “瓷砖”网格。我有我的瓷砖坚持到我的数据库就好了,我有一个网页UI(通过Vaadin)设置,以便我可以查看他们就好了。到目前为止,我一直在用20x20的网格查看它们。MySQL JPQL查询性能问题

到目前为止,它似乎进展顺利。我可以坚持几组10,000块瓷砖,并且四处滚动看着它们,重新显示瓷砖几乎是瞬间的。然而,今天,我决定坚持一大堆瓷砖(准确地说是633,460),看看数据库中瓷砖的实际数量是多少。现在我在地图上滚动显示了一些重要的性能问题,因为我的MySQL数据库似乎在处理这么多磁贴时遇到了困难。

我使用的是由Hibernate支持的JPA 2.0。即使我直接进入数据库并运行SQL查询,响应时间也非常慢。

SELECT * FROM game.landtile WHERE xcoor < 999999061 AND xcoor > 999999040 
AND ycoor > 1000000140 AND ycoor < 1000000161; 

我刚刚运行该查询以获得400个地物,它在MySQL中有3.5秒的持续时间和7.25秒的读取时间!如果我第二次运行相同的查询,则持续时间为0.5秒,提取时间为0.1秒。 500毫秒我可以忍受... 7000我不能。

我对landtile实体看起来是这样的:

@Entity 
@Table(name = "LandTile", uniqueConstraints = {@UniqueConstraint(columnNames={"XCoor", "YCoor"})}) 
public class LandTile extends AbstractMapValues implements Serializable { 

    private static final long serialVersionUID = 1L; 

    @Id 
    @Column(name = "LandTileId") 
    private String landTileId; 

    @Column(name = "XCoor") 
    @Index(name = "XCoordinateIndex") 
    @Range(min = 0, max = MAX_MAP_INT) 
    private int xCoor; 


    @Column(name = "YCoor") 
    @Index(name = "YCoordinateIndex") 
    @Range(min = 0, max = MAX_MAP_INT) 
    private int yCoor; 

    @OneToOne(cascade = CascadeType.ALL) 
    private Building building; 

    @OneToOne(cascade = CascadeType.ALL) 
    private Road road; 

    private boolean river; 

    @OneToMany(mappedBy="expeditionLocationLandTile") 
    private Set<Expedition> expeditionsAtThisLocation; 

    @ManyToMany(
      mappedBy = "discoveredLandTiles", 
      targetEntity = Player.class 
     ) 

    private Set<Player> playersThatHaveDiscovered; 

    @ManyToMany(
      mappedBy = "routeListOfLandTiles", 
      targetEntity = Expedition.class 
     ) 
    private List<Expedition> expeditionRouteThisIsPartOf; 

    @ManyToOne 
    @JoinColumn(name="FiefdomOfCapitalCity", unique=true) 
    private Fiefdom fiefdomOfCapitalCity; 

    @ManyToOne 
    @JoinColumn(name="ActualOwningFiefdomId", unique=true) 
    private Fiefdom actualOwningFiefdom; 

    @ManyToOne 
    @JoinColumn(name="DefaultOwningFiefdomId", unique=true) 
    private Fiefdom defaultOwningFiefdom; 

还有另外18分简单的INT列我这里就不一一列举。

所以基本上我希望你们能帮我弄清楚我的选择是什么。正如你所看到的,在landtile和我的其他模型之间有很多关系,对于这样的游戏,整个数据集本身就是高度关系的,这就是为什么我首先使用SQL数据库的原因。但是现在我担心性能会变得如此糟糕,以至于我应该停止开发新功能,并且重新整理我的整个DAO层(希望它只能是...)来使用NoSQL数据库,并且处理与我所有的关系在Java中。

看起来像MongoDB的已经内置支持2D网格:

http://blog.codecentric.de/en/2012/02/spring-data-mongodb-geospatial-queries/

我打算大概主办我在亚马逊的游戏和使用Amazon Elasti缓存。我的游戏地图数据可能会大部分时间停留在二级缓存(通过休眠),因此我不会有这种可怕的表现吗?我真的认为我遇到的唯一真正的性能问题将是在愚蠢的地图上滚动!

+1

你有没有试过对你的查询做一个解释计划?它是否使用你的指数?您是否尝试过在[XCoor,YCoor]上定义索引? – 2013-02-22 07:56:36

+0

它看起来像是由于我的@Index(name =“XCoordinateIndex”),我的MySQL表在这些字段上有以下索引:只有“xcoor”复选框的索引和只有“ycoor”复选框的索引。还有一个名为“Xcoor”的类型为“Unique”的索引,其中XCoor和YCoor都选中了复选框。这是由于我的表注释:@Table(name =“LandTile”,uniqueConstraints = {@UniqueConstraint(columnNames = {“XCoor”,“YCoor”})})所以我不认为索引是问题;他们应该已经成为一对索引。 – CorayThan 2013-02-22 08:07:36

+1

不要猜测。要求MySQL向您解释查询计划,并查看是否使用了您的索引。 – 2013-02-22 08:09:13

回答

0

我的数据是空间数据,MySQL的InnoDB引擎不支持空间索引。 MyISAM引擎可以,但它不支持事务或外键。请参阅the MySQL documentation

我决定使用支持复杂关系,事务和外键的数据库,而不是牺牲事务和外键,因此我将整个项目切换为使用Neo4j graph database