Author Topic: Database Object vs. NWNx vs. NBDE  (Read 1365 times)

Legacy_BelowTheBelt

  • Hero Member
  • *****
  • Posts: 699
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« on: May 26, 2011, 04:49:10 am »


               Hey,

I'm looking for some insight into when and were is the best place to use each.  My mod uses all 3, leaning most heavily on a database object to store player specific info.  NDBE stores server quest info, and NWNx/SQL used to store some other system info.

I thought I read somewhere that NBDE was actually faster than NWNx in some instances (reading the DB on smaller modules, perhaps?)

Also, how many variables can you store on a DB object before it starts impacting performance (my DB object is probably storing a couple dozen variables for each player)?

I know that a lot of this depends on the robustness of the server, but possibly there are some best practices to guide the use of each of these?
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #1 on: May 26, 2011, 07:10:02 am »


               I didnt knew sing both nwnx odbc and bio db is possible or you just using bio db only for non-object purposes/you disabled SCORCO hook?

The only thing whats faster on bid DB is reading, its the saving whats the problem and NDBE doesnt help with this.
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #2 on: May 26, 2011, 04:52:58 pm »


               Unless you are dealing with a couple thousand variables on your items you shouldn't see any performance impact. I use a database item for pretty much any variable that pertains specifically to that player. Location, deaths, kills, quests, etc. I don't know of any particular reason why someone would need to store thousands of variables on an item but I guess it could happen.

To this day I still haven't needed to use an external database via NWNx for anything. I do know that it is much faster than using bioware's but I've only needed to store/read a couple integers so bioware's has worked fine for me. I also use bioware's for persistent item storage for players and have not had any issues thus far(storing/retrieving creature with items method).

If you need to use a lot of different types of variables that don't pertain to one individual player and will be retrieving and storing them often, then NWNx + database is the way to go. When you store any type of variable in the bioware database, other than an integer, and then need to update that variable, it isn't actually replaced. The old one is marked as unused or what not and the new variable is written. This is what causes the bloating in the bioware database and then causes more read/write problems. That is why people prefer to use NWNx + external database in these instances.

Hope the info helps. And hopefully I didn't make anything more confusing.
               
               

               


                     Modifié par GhostOfGod, 26 mai 2011 - 03:57 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #3 on: May 26, 2011, 06:26:32 pm »


               I think the two previous replies mostly covered your question. I actually learned something from GoG's, assuming he's right about the causes of the database bloat (and the explosion that follows), and it does seem to conform to my muddled recollection of prior explanations.

The thing they miss is the flexibility of SQL using NWNX. Yes, it's better in terms of raw power, and yes, database objects will work for most things.

However, if you use a SQL database, you can access, compare, and modify that data FAR more easily than with any other system. Not only that, you can mass edit it at any time, and don't need to look at a character file to do it. I can, using MySQL, for example:

1) pull up a list of all banned player cd keys
2) pull up a list of all instances of item with resref 'blah' in our bank vaults (handy when a player loses something)
3) rebalance the weighting of our random loot  properties (our random-loot system is entirely database-driven)
4) check how many players are tagged with a certain subrace
5) check how many cd keys are bound to a player's account, and add/remove one or more
6) un/ban a player
7) set up interserver messaging, and rebroadcast it to rss feed and web page
8) make dynamically changing encounter and loot tables
9) generate and compare data on run and area  times, frequency

And so on. It's also able to handle twice the bits of NWN. If you're planning to develop for any amount of time, NWNX-MySQL is the way to go. Data stored on database items is fast, but generally inacessible. Far better to call up database vars on login and set as locals for speedy access.

Funky
               
               

               
            

Legacy_BelowTheBelt

  • Hero Member
  • *****
  • Posts: 699
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #4 on: May 26, 2011, 10:16:18 pm »


               Thanks, all.

With SQL, I've been slow to fully use it (rather than a database object) for PC variables because of the transient nature of players and the need to archive.  To my mind it seems that normally with SQL, there ends up being lots of different DB tables created to house different sorts of data.  Not sure if this aids in the speed of the reading or not, but conceptually, I'd rather have a single DB table with each record being a unique PC and having lots of data columns containing different data about that PC.  This seems like it would be the easiest to manage and modify.  Also, if a record hadn't been accessed in a period of time (6 months, maybe), I could then archive a single record to another file, rather than having to archive many different tables that would contain little bits of data about a player.  Is that how others have it set up?  Or, do you have many different tables housing specific data types?

By using a database object, if the player leaves, then the DB isn't stuck warehousing the variables.  I can easily move a bic file to an alternate storage location.  Yes, I'm stuck not being able to modify the data, nor modify it more than one PC at a time.  

Love the idea of reading the DB and putting it on the player at login.  Maybe I'll get there if I can get my hands around putting all my DB calls into one table (provided that's as good a solution as multiple tables).

Also, how do others manage the archiving/back up process?  What systems do you use?
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #5 on: May 26, 2011, 10:47:44 pm »


               Database item is appreciated also because you can test it from toolset via F9. Testing anything using NWNX database is not so easy/fast. So appreaciated for everything player related.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #6 on: May 26, 2011, 11:59:05 pm »


               

GhostOfGod wrote...

  When you store any type of variable in the bioware database, other than an integer, and then need to update that variable, it isn't actually replaced. The old one is marked as unused or what not and the new variable is written. This is what causes the bloating in the bioware database and then causes more read/write problems. That is why people prefer to use NWNx + external database in these instances.
.


You are correct on the int not causing bloat.   But it is not the only Data type that does not cause the bloat. 
There are really ony  Two Campaign data types that get marked as unused and never written over in the DB.  They ar the SetCampaignString and StoreCampaignObject.    All Of the other DataTypes get written ove and do not cause over bloating of the NWN db. 

Explaintion.
All of the Data Types except for the two ( String and Object)  Have a fixed size.  Yes the sizes are different but each type's size is fized.   An int will never be larger then 32 bits or 9 digits when converted to a text string, which the NWN DB unfortiantly does.  Likewize a location will never be larger then the 6 floats and one object id that it is mad up of making it about 70 bytes in length when it is stored into the DB.   

Makeup of the nwn DB.  

The data base is made up of three files  they are.  
.cdx   --  As far as I can tell this is a Index of the VarNames in the DB.  
.ftp  --   This is where all data that is not a known length is stored.  the Data is pointed to from the .dbf  entry.
.dbf  --  A list of structures for each entry in the DB.  The structures are all around 640 bytes long.  128 bytes of that is for the storage of data for any of the known length data types.   

If the data being stored is of one of the known length types the data is just stored in the .dbf file and overwritten if changed.   

if the data is of the unknown length type. it is written to the end of the .ftp file and a pointer to the data is written to the .dbf file.   This is where the data base bloat comes from since the old data is never removed from the .ftp file.  So in truth the data is never marked a unused there is just no longer anything point at it to be used.  It is sad that even if you write the same string to the DB twice back to back you end up with it twice in the .ftp file.  

I hope this opens up for you a little better what vars cause DB bloat and which one do not, So that you can use them wisely.  

L8   
               
               

               
            

Legacy_GhostOfGod

  • Hero Member
  • *****
  • Posts: 1490
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #7 on: May 27, 2011, 02:20:04 am »


               Ah ha. Well that clears things up for me too. Thank you Lightfoot. I was going off of what I remembered reading in the past.

So locations are ok and do not cause bloat? Do they store the area associated to the locations as an object or is it just an object ID(integer)? I'm a bit confused about that part. How is the area being stored in the location different than an object being stored?
               
               

               


                     Modifié par GhostOfGod, 27 mai 2011 - 01:22 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #8 on: May 27, 2011, 04:02:33 am »


               If you look in Boiware's Documentation: Common Game GFF Structures  you can see how a location is defined.  The  struct in script would be:

struct location
{
     dword   Area;                     //ObjectId of the area containing the location

     float       OrientationX;      //(x,y,z) components of the direction vector in    
     float       OrientationY;     //which the location faces 
     float       OrientationZ;

     float        PositionX;
     float        PositionY;        //(x,y,z) coordinates of the location
     float        PositionZ; 
}

So yes it is only storing the 32 bit dword ID. 
               
               

               


                     Modifié par Lightfoot8, 27 mai 2011 - 09:18 .
                     
                  


            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #9 on: May 27, 2011, 04:27:50 am »


               

BelowTheBelt wrote...

Thanks, all.

With SQL, I've been slow to fully use it (rather than a database object) for PC variables because of the transient nature of players and the need to archive.  To my mind it seems that normally with SQL, there ends up being lots of different DB tables created to house different sorts of data.  Not sure if this aids in the speed of the reading or not, but conceptually, I'd rather have a single DB table with each record being a unique PC and having lots of data columns containing different data about that PC.  This seems like it would be the easiest to manage and modify.  

That's part of the flexibility of SQL. You can set up tables however you like. We have some 84 tables, but you could certain set up a table for each player, or each character, automatically - it all depends on wha you need.

Here are our tables, by way of comparison:
+----------------------+
| Tables_in_nwn        |
+----------------------+
| arena                |
| bankchest_items      |
| delete_block         |
| donor_list           |
| fkymessageboard      |
| guild_list           |
| hardcore             |
| hgll_feats           |
| market               |
| objdata              |
| pcvars               |
| plvars               |
| portrait_duplicate   |
| pwdata               |
| qs_quests            |
| qs_status            |
| qs_synonyms          |
| reinc_items          |
| reinc_slots          |
| reinc_subexception   |
| respawn_loss         |
| rip_augments         |
| rip_augprops         |
| rip_augvars          |
| rip_props            |
| rip_safe_patterns    |
| server_list          |
| simtools             |
| sort_100             |
| sort_110             |
| sort_111             |
| sort_112             |
| sort_113             |
| sort_114             |
| sort_115             |
| sort_116             |
| sort_117             |
| sort_118             |
| sort_119             |
| sort_210             |
| sort_211             |
| sort_212             |
| sort_213             |
| sort_214             |
| sort_215             |
| sort_216             |
| sort_217             |
| sort_218             |
| sort_219             |
| sort_310             |
| sort_311             |
| sort_312             |
| sort_313             |
| sort_314             |
| sort_315             |
| sort_316             |
| sort_317             |
| sort_318             |
| sort_319             |
| sort_410             |
| sort_411             |
| sort_412             |
| sort_413             |
| sort_414             |
| sort_415             |
| sort_416             |
| sort_417             |
| sort_418             |
| sort_419             |
| sub_abilities        |
| sub_appearances      |
| sub_feats            |
| sub_languages        |
| sub_list             |
| sub_skills           |
| sub_usable           |
| user_early           |
| user_list            |
| user_message_history |
| user_messages        |
| user_passwords       |
| user_totals          |
| wallet_balance       |
| wallet_history       |

The sort tables are used for on-the-fly sorting of lists, one per server instance (for instance, alphabetizing feats in the legendary leveler, or spells in the spell swapper), and are usually empty. Note that each table is defined according to the specific needs of the user, with as many columns of whatever data type you want to store. Any way you set it up, it's pretty easy to manage.

Also, if a record hadn't been accessed in a period of time (6 months, maybe), I could then archive a single record to another file, rather than having to archive many different tables that would contain little bits of data about a player.

I'm a little unclear on the terminology you're using, but bloat really isn't an issue. We use the database extensively, with one of if not the largest servervaults out there, and are still only at a couple Gigs - and we don't purge back records, ever (we've had players return after a 6 year lull). If we wanted to, though, it'd be easy, whether or not we'd set up one table per character, per player, or for all pc variables (the last is what we did). This is my point - SQL is enormously flexible, allowing you to do whatever it is you want to do with relative ease.

I'll offer an example of how we would purge old records, which also allows me to highlight SQL's one downside - the need to forge an indelible link between bic file and database table. We do this via a Unique ID, which is set in the character's tag field (otherwise unused), along with some other data. It's based on UNIX time, server number, and an incrementing counter, so is guaranteed unique. It's what is referenced when the pc enters the server, to load stored vars onto it. Here's an excerpt from our pcvars table (first, the table info):

mysql> describe pcvars;;
+----------+-----------------------------------------------------------+------+-----+-------------------+-------+
| Field    | Type                                                      | Null | Key | Default           | Extra |
+----------+-----------------------------------------------------------+------+-----+-------------------+-------+
| pcv_uid  | varchar(32)                                               | NO   | PRI | NULL              |       |
| pcv_type | enum('int','float','string','object','vector','location') | NO   | PRI | NULL              |       |
| pcv_key  | varchar(64)                                               | NO   | PRI | NULL              |       |
| pcv_val  | text                                                      | YES  |     | NULL              |       |
| pcv_last | timestamp                                                 | NO   |     | CURRENT_TIMESTAMP |       |
+----------+-----------------------------------------------------------+------+-----+-------------------+-------+

Here are a few sample rows:

mysql> select * from pcvars limit 5;
+------------------+----------+---------------------+---------+---------------------+
| pcv_uid          | pcv_type | pcv_key             | pcv_val | pcv_last            |
+------------------+----------+---------------------+---------+---------------------+
| 100-1255280229-1 | int      | Filters             | 320     | 2010-07-04 09:47:53 |
| 100-1255280229-1 | int      | FKY_CHAT_LANGBASE   | 1       | 2009-10-12 07:44:56 |
| 100-1255280229-1 | int      | FKY_CHAT_TRUEAPPEAR | 6       | 2010-07-04 05:38:11 |
| 100-1255280229-1 | int      | Guild               | 34      | 2010-07-29 09:59:15 |
| 100-1255280229-1 | int      | ResumeRests         | 1       | 2009-11-28 02:36:00 |
+------------------+----------+---------------------+---------+---------------------+

Now, I just pulled up the first 5 of 580,612 rows in the table (count(*) is another very handy MySQL feature), which all happen to belong to the same pc (identical uid column). The variable name is in the key column, and the value in the val column (note all columns are prefixed by pcv_ for the purpose of joins (table comparisons)). The pcv_last column is when the variable was last modified - in most cases, when it was set. The type column is pretty self exaplanatory (type of variable). If I wanted to set up a system that purged old pc vars, I would maintain a table that tracked last login date of each UID. On each mod load, I would do a select from that table for dates over x months old (or what have you), and if any came up, simply DELETE FROM pcvars where pcv_uid = 'blah'; Blah would be 100-1255280229-1 if I wanted to delete all the vars belonging to the character whose uid that is.

 Is that how others have it set up?  Or, do you have many different tables housing specific data types?

As you can see above, our stuff is largely organized by system. I think having one table per pc would be enormously clunky, and bad normalization, but it might be a reasonable solution if you're not using MySQL, and have no other way to purge old data. Typically, you want to store data in ways that is non-duplicative, and in discrete chunks. That's why all the random item property (rip_) tables are kept seperate from the older and mostly defunct pwdata (the generic table that NWNX uses for beginners).


By using a database object, if the player leaves, then the DB isn't stuck warehousing the variables.  I can easily move a bic file to an alternate storage location.  Yes, I'm stuck not being able to modify the data, nor modify it more than one PC at a time.

You're not stuck with that if you use MySQL, either, regarless of how you set up your tables.

Love the idea of reading the DB and putting it on the player at login.  Maybe I'll get there if I can get my hands around putting all my DB calls into one table (provided that's as good a solution as multiple tables).

A single unitary table is likely a very bad idea, though it's a good idea for player variables called up on login (hence our pcvars table).

Also, how do others manage the archiving/back up process?  What systems do you use?

We run weekly (or twice-weekly, forget) backups, but I don't know the ins and outs - benefits of having a network administrator as your co-admin. '<img'>

Funky
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #10 on: May 27, 2011, 04:35:01 am »


               

ShaDoOoW wrote...

Database item is appreciated also because you can test it from toolset via F9. Testing anything using NWNX database is not so easy/fast. So appreaciated for everything player related.

Actually, this is a nonissue, if you use the right set up. We have a dev environment set up using VirtualBox that only takes about 60 seconds to load or reset - our module takes roughly the same amount of time to get rolling in F9 test mode. This is, in part, due to lots of scripts scheduled to run throughout the first minute, but the speed difference between the two is small.

Funky
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #11 on: May 27, 2011, 04:38:38 am »


               

So yes it is only storing the 32 bit dword ID. 


If that's the case, it'd be subject to breakage when the module was edited, no? Or is that a known issue? It's been like 6 years since I used the biodb, I barely remember the nitty gritty.

Funky
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #12 on: May 27, 2011, 04:58:26 am »


               

FunkySwerve wrote...

So yes it is only storing the 32 bit dword ID. 


If that's the case, it'd be subject to breakage when the module was edited, no? Or is that a known issue? It's been like 6 years since I used the biodb, I barely remember the nitty gritty.

Funky



Yes, It is a known issue.  I think the most common workaround for non nwnx users is to store the Tag for the area.  Then replace the area n the location after finding the area by its tag.    

Of cource the area ID's will only change if you add or remove areas to the module.   That is of little comfort though since most active worlds are adding areas all the time.
               
               

               
            

Legacy_virusman

  • Sr. Member
  • ****
  • Posts: 448
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #13 on: May 27, 2011, 10:05:06 pm »


               

FunkySwerve wrote...

ShaDoOoW wrote...

Database item is appreciated also because you can test it from toolset via F9. Testing anything using NWNX database is not so easy/fast. So appreaciated for everything player related.

Actually, this is a nonissue, if you use the right set up. We have a dev environment set up using VirtualBox that only takes about 60 seconds to load or reset - our module takes roughly the same amount of time to get rolling in F9 test mode. This is, in part, due to lots of scripts scheduled to run throughout the first minute, but the speed difference between the two is small.

Funky



Also, there is NWNCX + plugin that attaches all NWNX plugins to the client, allowing to test the module without running on a dedicated server.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Database Object vs. NWNx vs. NBDE
« Reply #14 on: May 28, 2011, 02:19:45 am »


               You mean Elgar's, VMan?

Funky