2013-02-22 63 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