My questions comes first, then I'll describe the whole situation and current solution:
Questions.
1. Why could mySQL make enormously lots of continous read|write (300-1000 megaBytes) disk operations?
2. Is DB structure optimal (need advice otherwise)?
3. Do UniqueKey could slow down DB?
4. What could be better solution for the situation?
5. At the end vServer is getting down and I got mail with ~'ETIMEDOUT: Connection timed out - connect (2)'; So maybe issue is not in DB structure but it is some misconfiguration?
Situation.
Users on the end devices are playing and when gameover comes they are storing game records in central DB. Users could see highscores table sorted by hignscore.
I cant say that there are a lot of users. Lets assume that 1 user per 1 min.
Solution.
LAMP.
Since there are several similar games that users are playing there are several similar tables+views pairs in DB. (~25 Tables+25 Views total). Most of tables contain ~30 000 records. 3 of them contain up to 150 000 records.
In order to store users uniquely: 1user-1record I made a unique key UNIQUE INDEX userid (userid, gamename, gametype, recordvalue).
Since user should see sorted values (highscores) I made a view for a table that shows what is needed. So the external php script is working with view rather then with table.
CREATE TABLE supergameN (
id INT(11) NOT NULL AUTO_INCREMENT,
userid VARCHAR(255) NOT NULL,
username VARCHAR(50) NOT NULL,
gamename VARCHAR(100) NOT NULL,
gametype VARCHAR(100) NOT NULL,
description VARCHAR(100) NULL DEFAULT 'empty',
recordvalue INT(11) NOT NULL,
PRIMARY KEY (id),
UNIQUE INDEX userid (userid, gamename, gametype, recordvalue)
)
CREATE VIEW supergameN_view AS
SELECT
id,
userid,
username,
gamename,
gametype,
description,
recordvalue
FROM supergameN
ORDER BY gametype, recordvalue DESC
Thanks in advance. Alex.
Maybe not the solution but something I noticed:
Leave out the recordvalue from the unique key, since otherwise you would allow several records to exist for each userid-gamename-gametype combination, as long asd they have different recordvalues!
By using
UNIQUE INDEX userid (userid, gamename, gametype)
You ensure that per game and user you only ever store one result.
And, some further remarks/questions:
Do you really need two columns to identify the game?
What is kept in description: is it user or game related?
Maybe you could normalize a bit by having just a gameid column in your main table and (assuming that description refers to the game) a separate table games with columns gameid, gamename,gametypeand description. And then, of course, there would be no need to keep id anymore, instead you would have the combination of (userid,gameid) as your primary key.
Related
I'm going to keep it brief here for convenience's sake. I'm new to SQL coding, so please excuse me if I say something weird.
I did not manage to find a solid solution to it (at least one that I would truly understand), which is precisely why I'm posting here as a last resort at this point.
The table code:
create table companies (
company_id mediumint not null auto_increment,
Name varchar(40) not null,
Address varchar(40),
FoundingDate date,
primary key (company_id)
);
create table employees (
Employee_id mediumint not null auto_increment,
Name varchar (40),
Surname varchar(40),
primary key (Employee_id)
);
create table accounts (
Account_id mediumint not null auto_increment,
Account_number varchar(10) not null,
CompanyID int(10),
Date_of_creation date,
NET_value int(30),
VAT int(3),
Total_value int(40),
EmployeeID int(10) not null,
Description varchar(40),
primary key (Account_number)
);
Table values are random strings and numbers until I figure this out.
My issue is that I'm stuck at forming correct SQL queries, namely:
Query all accounts with their designated companies. I need it to show 'NULL' value if an account has no associated company.
Query that can list all accounts whose date is less than 2018-03-16 or those without a date.
Query that will print the description of the 'Accounts' table in one column and the number of characters in that description in a different column.
Query that lists all employees whose names end with '-gh' and that have names greater than 5 characters in length.
Query that will list the top total sum amount.
Query that will list all accounts that have '02' in them (i.e. 3/02/05).
If you can answer at least one of these queries and if you can explain how you got to the solution in a simplistic manner, well... I'm afraid I have nothing to offer but honest gratitude! ^^'
Welcome to the community, but as Jerry commented, you should really try to show SOMETHING that you have tried just to show what you THINK is needed. Also, don't just add comments to respond, but edit your original post with additional details / data as people ask questions.
To try and advance you forward though, I will point out two specific links that should help you out. The first one is a link for the basics on querying explaining the
select [fields] from [what table] join [other tables] where [what is your criteria] -- etc. Some Basics on querying
The next give some very good clarification on JOIN conditions of (INNER) JOIN -- which means required record match in BOTH tables being joined, and FULL OUTER JOINS, LEFT JOINs, etc.
After reviewing those, if you STILL have questions, please edit your original question, post some samples of what you THINK is working and let us know (or comment back to a specific answer), and we in the forum can follow-up with you.
HINT, your first query wanting NULL you should get from the visual link via LEFT JOIN.
A visual representation and samples on querying
I have a tables called userAccounts userProfiles and usersearches.
Each userAccount may have multiply Profiles. Each user may have many searches.
I have the db set up working with this. However in each search there may be several user profiles.
Ie, each user account may have a profile for each member of their family.
They then want to search and include all or some of their family members in their search. The way i would kinda like it to work is have a column in user searches called profiles and basically have a list of profileID that are included in that search. (But as far as i know, you can't do this in sql)
The only way i can think i can do this is have 10 columns called profile1, profile2 ... profile10 and place each profileid into the column and 0 or null in the unused space. (but this is clearly messy )
Creating columns of the form name1...nameN is a clear violation of the Zero, One or Infinity Rule of database normalization. Arbitrarily having ten of them is not the right approach, that's an assumption that will prove to be either wildly generous or too constrained most of the time. Since you're using a relational database, try and store your data relationally.
Consider the schema:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
name VARCHAR(255),
UNIQUE KEY index_on_name (name)
);
CREATE TABLE profiles (
id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
user_id INT NOT NULL,
name VARCHAR(255),
email VARCHAR(255),
KEY index_on_user_id (user_id)
);
With that you can create zero or more profile records as required. You can also add or remove fields from the profile records without impacting the main user records.
If you ever want to search for all profiles associated with a user:
SELECT ... FROM profiles
LEFT JOIN users ON
users.id=profiles.user_id
WHERE users.name=?
Using a simple JOIN or subquery you can easily exercise this relationship.
I am working in a project. In my project database, I have student and trainer. I need to use auto-increment with alpha-numeric for student id and trainer id.
For example:
student id should be automatically incremented as STU1,STU2....
trainer id should be automatically incremented as TRA1,TRA2....
I am using MySQL as my DB.
If it is possible, please give solution for other databases like oracle, Sql server.
MySQL does not have any built in functionality to handle this. If the value you want to add on the front of the auto incremented id is always the same, then you should not need it at all and just add it to the front in your SELECT statement:
SELECT CONCAT('STU', CAST(student_id AS CHAR)) AS StudentID,
CONCAT('TRA', CAST(trainer_id AS CHAR)) AS TrainerID
FROM MyTable
Otherwise the following would work for you:
CREATE TABLE MyTable (
student_id int unsigned not null auto_increment,
student_id_adder char(3) not null
trainer_id int unsigned not null auto_increment,
trainer_id_adder char(3) not null
)
The SELECT to pull them together might look like the following:
SELECT CONCAT(student_id_adder, CAST(student_id AS CHAR)) AS StudentID,
CONCAT(trainer_id_adder, CAST(trainer_id AS CHAR)) AS TrainerID
FROM MyTable
You are mixing two different concepts here. The autoincrement feature is for ID based database tables.
You can build a student table where each student gets an ID, which can be a number or something else and will probably be printed in the student card. Such a table would look like this:
Table student
student_card_id
first_name
last_name
...
There can be other tables using the student_card_id. Now some people say this is good. Students are identified by their card IDs, and these will never change. They use this natural key as the primary key in the table. Others, however, say that there should be a technical ID for each table, so if one day you decide to use different student numbers (e.g. STUDENT01 instead of STU01), then you would not have to update the code in all referencing tables. You would use an additional technical ID as shown here:
Table student
id
student_card_id
first_name
last_name
...
You would use the ID as primary key and should use the auto increment feature with it. So student STU01 may have the technical ID 18654; it just doesn't matter, for it's only a technical reference. The student card will still contain STU01. The student won't even know that their database record has number 18654.
Don't mix these two concepts. Decide whether you want your tables to be ID based or natural key based. In either case you must think of a way to generate the student card numbers. I suggest you write a function for that.
I am currently developing a database storage solution for product inventory information for the company I work for. I am using MySql, and I am having a hard time coming up with an efficient, feasible format for the data storage.
As it works right now, we have ~25000 products to keep track of. For each product, there are about 20 different categories that we need to track information for(quantity available, price, etc..). This report is downloaded and updated every 3-4 days, and it is stored and updated in excel right now.
My problem is that the only solution I have come up with so far is to create separate tables for each one of the categories mentioned above, using foreign keys based off of the product skus, and cascading to update each respective table. However, this method would require that every table add 24000 rows each time the program is run, given that each product needs updated for the date it was run. The problem with this is that the data will be store for around a year, so the tables will grow an extensive amount. My research for other database formats has yielded some examples, but none on the scale of this. They are geared towards adding maybe 100 rows a day.
Does anybody know or have any ideas of a suitable way to set up this kind of database, or is the method I described above suitable and within the limitations of the MySql tables?
Thanks,
Mike
25,000 rows is nothing to MySQL or a flat file for that case. Do not initially worry about data volume. I've worked on many retail database schemas and products are usually defined by either a static or arbitrary-length set of attributes. Your data quantity ends of not being that far off either way.
Static:
create table products (
product_id integer primary key auto_increment
, product_name varchar(255) -- or whatever
, attribute1_id -- FK
, attribute2_id -- FK
, ...
, attributeX_id -- FK
);
create table attributes (
attribute_id integer primary key -- whatever
, attribute_type -- Category?
, attribute_value varchar(255)
);
Or, you obviously:
create table products (
product_id integer primary key auto_increment
, product_name varchar(255) -- or whatever
);
create table product_attributes (
product_id integer
, attribute_id integer
, -- other stuff you want like date of assignment
, primary key (product_id , attribute_id)
);
create table attributes (
attribute_id integer primary key -- whatever
, attribute_type -- Category?
, attribute_value varchar(255)
);
I would not hesitate to shove a few hundred million records into a basic structure like either.
I am trying to design a user table for MySQL.
for now, my user table looks like this
users (
BIGINT id,
VARCHAR(?) username,
VARCHAR(?) password,
VARCHAR(254) email,
DATETIME last_login,
DATETIME data_created
)
what other fields should I also include and why do I need them?
what fields should I exclude from above and why?
how many characters should I allocate for username and password, and why?
should I use BIGINT for id?
Thank you in advance for your helps.
ADDED
I am going to use the table for social web site, so 'users' mean people around the world.
A few comments:
BIGINT is fine. I assume you're using it as a surrogate key. In that case, declare it as
BIGINT id primary key auto_increment,
Mysql will automatically allocate a unique int value to your id whenever you do an insert (don't specify any value for this field). Never try to implement this behaviour by selecting the max id and adding 1 to it (I've seen this so many times).
Length of username and password: this is no big deal really, just pick a length. I tend to standardise on 255 length varchars for these things but that's not based on anything empirical.
Call your table "user", not "users". Conceptually, a table implements an entity in the same way that a class implements an entity. You will likely create a class or data structure called "user" and the table name should correspond to this.
Every table that I create has two timestamps, "created" and "last_updated". You're halfway there:)
I don't think I would store last_login in the user table, this is likely to be something that you will want to log in a separate table. It's a good idea to store all login events (login, logout, failed attempt, account lock etc.) in a logging table. This will give you much better visibility of what the system has been doing.
1/ Username and password: decide for yourself how large you want these to be.
2/ BIGINT is fine, even though an integer probably suffices. But make it UNSIGNED and probably AUTO_INCREMENT, too.
3/Try keeping your Users table as small as possible:
users (
BIGINT id,
VARCHAR(?) username,
VARCHAR(?) password,
VARCHAR(254) email,
DATETIME data_created
)
The rest, you put in extra tables:
logins (
BIGINT loginid
BIGINT userid
DATETIME last_login,
VARCHAR(15) IP_ADRESS
...
)
This way, your users table will only change when a new user is added or deleted, or when someone changes his password, which is less frequently then when someone logs in. This allows for better table caching (MySQL clears the table cache when you write to the table).
All that just depends on your own specs. For username you could take 100 if you like, for password take the length of the hashing function you want to use (32 for MD5).
It's more common to use INTEGER(10) with AUTO_INCREMENT on the primary key of a table.
You might want to ask for a name, surname, birth date, place of living, etc. Think that all the data you ask the user for should be somehow important to the platform that you are building.