How to transfer items between users in MySQL safely? - mysql

I'm using MySQL with InnoDB tables.
I have a USERS table like this:
ID MONEY APPLES
1 10 5
2 500 0
USER 1 selling 1 apple to USER 2. (1 apple costs 50 money.)
How to do it safely in MySQL?

You will want to wrap the two UPDATE statements required in one TRANSACTION
see http://dev.mysql.com/doc/refman/5.6/en/innodb-transaction-model.html

Related

Does MySQL compress query responses?

I am currently trying to optimise some DB queries that get run a lot, the queries are run by using a SELECT query against a view, this view does a lot of joins. I thought I might be able to speed things up by caching the results of the view into a table and selecting from the table instead of the view.
Let's say I have 2 tables
People:
PersonId
Name
1
Anne
2
Brian
3
Charlie
4
Doug
CustomerPeople:
CustomerId
PersonId
1
1
1
2
1
3
1
4
2
1
2
2
and I have a view that joins the two tables to give a list of people, by name, belonging to the customer:
CustomerId
PersonName
1
Anne
1
Brian
1
Charlie
1
Doug
2
Anne
2
Brian
When I query the view, I look at the Duration/Fetch and it is 0.10 sec/4.00 sec
I decide to cache the view data into a table and create a new table:
CustomerNamedPeople
CustomerId
PersonName
1
Anne
1
Brian
1
Charlie
1
Doug
2
Anne
2
Brian
Which contains the exact same data, however now when I query the table, I look at the Duration/Fetch and it is 0.05 sec/6.00 sec
My understanding is the Duration is the time it takes MySQL engine to run the query, and Fetch is the time it takes the data to be returned to the client (over the network). Unsurprisingly the Duration was faster, and took only 50% of the time, which makes sense, there is no longer a join occurring, however the Fetch took 150% of the time, and is slower.
My question here is: Does MySQL do some sort of response stream compression, since it knows that Anne and Brian are repeated, it can send them only once and have the client "decompress" the data?
The reason I ask is because I am doing something similar but with 1,000,000 rows returned, the data in the two responses is identical, but the view Fetch takes 20 seconds, and the table Fetch is 60 seconds, most of the PersonNames are repeated more than once, so I am wondering if perhaps there is some sort of compression occurring in the response, should I not expect MySQL to take the same time to Fetch two sets of identical data?

DB design little or too much data

I'm currently working on a little project that uses MySQL. However I'm struggling with the database design. Currently I've come up with 2 designs, one stores more data but is actually the way I want it to be, however this way makes it really hard to work with the data. The other way is I think more basic and simplifies a lot of things but stores less data.
Design 1
Example data items table
id
description
time_created
1
Car
2021-04-17 17:30:00
2
Bike
2021-04-17 17:30:00
Example data user_items table
id
user_id
item_id
time_achieved
1
1
1
2021-04-17 17:30:04
2
1
1
2021-04-17 17:30:03
3
1
1
2021-04-17 17:30:17
4
1
1
2021-04-17 17:30:22
5
1
1
2021-04-17 17:30:34
6
1
2
2021-04-17 17:30:42
7
1
2
2021-04-17 17:30:54
Design 2
Example data items table
id
description
time_created
1
Car
2021-04-17 17:30:00
2
Bike
2021-04-17 17:30:00
Example data user_items table
id
user_id
item_id
count
1
1
1
5
2
1
2
2
Basically we have items that can be anything, they include a description to specify what they actually are. A user can collect items (a lot). These are stored in the user_items table which contains a FK user_id and item_id to the users and items table. The users table is left out for simplicity.
As you can see design 1 stores a lot more rows for the user_items table, this allows us to add more information (time_achieved and more) per item that a user achieved. However this results in more rows and probably a harder time queriyng. Design 2 on the other hand simply adds a count column to determine how many items the user has, but this is very limiting because we cannot add more data (achieved time..) per user_item.
I'm not sure if design 1 is the right and only design for what we want to achieve. Basically we really want to store additional metadata per user_item but I just don't know if this is the right design since it quickly fills up the database. Does anyone have a suggestion/idea for an alternative design which stores less data than design 1 but still allows to add more info per user_item?
Thanks in advance.
Does anyone have a suggestion/idea for an alternative design which stores less data than design 1 but still allows to add more info per user_item?
Design 1 should work.
This design will also work but quickly fills up, more efficient.
id, item_id,Item_des,Item_qty,user_id,username,time_created all in one table.
some of the values will be repeated.

Duplicate or unpredictable results in MySQL

I'm trying to join a few tables in MySQL. Our setup is a little unique so I try to explain as good as I can.
I have a table 'INVENTORY' that represents the current items on stock.
These items are stored in a table 'COMPONENT'
Components are being used in installations.
Every user can have multiple installations and the same component can be used in multiple installation as well.
To uniquely map a component to an installation, it can be assigned to a PRODUCT. a product as has a 1-1 relationship with an installation. A component is not directly related to an installation
To finally assign a product to a specific installation a mapping table COMPOMENT_PRODUCT is used.
Example:
A component is like a part, lets say a screw. This screw is used in a computer. The very same screw can be used on multiple computers. But each computer can only be used on one specific installation.
TABLE COMPOMENT_PRODUCT
COMPOMENT_ID PRODUCT_ID
1 1
1 2
2 1
2 2
So we have the components C1 and C2 relevant for two installations.
TABLE INVENTORY
COMPOMENT_ID INSTALLATION_ID ON_STOCK
1 1 5
1 2 2
What I want to achieve
Now, I want to retrieve the inventory state for all components. But, not every component has an inventory record. In these cases, the ON_STOCK value from the inventory shall be NULL
That means, for this example I'd expect the following results
COMPOMENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 2
2 1 NULL
2 2 NULL
But executing this query:
SELECT DISTINCT
COMPONENT_PRODUCT.COMPONENT_ID,
COMPONENT_PRODUCT.PRODUCT_ID,
INVENTORY.ON_STOCK
FROM INVENTORY
RIGHT JOIN COMPONENT_PRODUCT ON COMPONENT_PRODUCT.COMPONENT_ID =
INVENTORY.COMPONENT_ID
returns the following resultset:
COMPONENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 5
1 1 2
1 2 2
2 1 (null)
2 2 (null)
Now, my next thought was, "of course, this is how joins behave, okay I need to group the results". But the way SQL works, the aggregation is not entirely predictable. SO when I
GROUP BY COMPONENT_PRODUCT.COMPONENT_ID,COMPONENT_PRODUCT.PRODUCT_ID
I get this result:
COMPONENT_ID PRODUCT_ID ON_STOCK
1 1 5
1 2 5
2 1 (null)
2 2 (null)
I have prepared a Fiddle here: http://sqlfiddle.com/#!9/71ca87
What am I forgetting here? Thanks in advance for any pointers.
Try this query -
SELECT DISTINCT
COMPONENT_PRODUCT.COMPONENT_ID,
COMPONENT_PRODUCT.PRODUCT_ID,
INVENTORY.ON_STOCK
FROM INVENTORY
RIGHT JOIN COMPONENT_PRODUCT ON COMPONENT_PRODUCT.COMPONENT_ID =
INVENTORY.COMPONENT_ID
AND COMPONENT_PRODUCT.PRODUCT_ID = INVENTORY.INSTALLATION_ID

Maintaining relationship and history in mysql databases

I am designing a mysql database and have come across these relations which will grow in the future.
Suppose Customer is tied to 2 different tables Policies and Options.
Each customer has multiple relationship with policies and likewise with options. Since I am keeping a details and history of the table as well every time I add a relation with customer, I will have to maintain another 2 tables. To calculate the price the customer owes, I will have to go thru customer_policies then customer_options and calculate the total price. Also the number of tables increases as the relationship increases.
If customer has a relation with policies it will have 2 tables -
customer_policies and customer_policies_details.
If customer has one more relation with options, it will add 3 more -
customer_options, and customer_option_history.
Like wise, it will keep on adding 2 more tables if there is one more
relation and the problem grows and grows.
I have tried 2 different options which I have mentioned below. I wanted to know what is the best way to solve this problem so that the table can be maintained as the relation grows.
Option 1:
customer_policies:
CustomerPolicyId CustomerId PolicyId Status
1 1 1 Active
2 1 2 Active
customer_policies_details:
CustomerPolicyDetailsId CustomerPolicyId Price
1 1 10
2 2 20
customer_options:
CustomerOptionId CustomerId OptionId Status
1 1 1 Active
2 1 2 Active
customer_options_details:
CustomerOptionDetailsId CustomerOptionId Price
1 1 10
2 2 20
Option 2:
Create a single table customer_selections and use Type and Id field instead like so:
customer_selections:
CustomerSelctionId CustomerId Type Id Status
1 1 Policy 1 Active
2 1 Policy 2 Active
3 1 Option 1 Active
4 1 Option 2 Active
customer_selection_details:
DetailsId CustomerSelctionId Price
1 1 10
2 2 20
3 3 10
4 4 20
To create a history of this I just have to create a customer_selections_details and keep track of all changes.
There should be better ways to solve this problem.

SQL query to identify max value in an subset of records to be used as boundary condition for Batch Job partitioning

I have around 2 million records in the database and I want to us the concept of partitions in one of my batch jobs. In order to do this I need to first identify the boundary records of the partition. Can anyone help out to identify boundry values using SQL query. To illustrate consider i have student records as follows
STUDENT_ID STUDENT_NAME
1 JACK
2 SPARROW
3 JONNY
4 WALKER
5 SKY
6 DANNY
Now if i want to create 2 partitions by boundary condition of first partition will be STUDENT_ID between 1 to 3 and STUDENT_ID between 4 to 6. consider similar situation incase student_id is a string or random id. How to identify the bounday condition. Currently I am thinking of first querying all the records in the database and then partitioning them in the java code. But if I have 2 million records this is highly not recommended what should i do in this condition?
You can use limit command in mySql as follow:
SELECT...
LIMIT y OFFSET x