Find all distinct alternate usernames by an ip in a single query - mysql

I'm trying to build a query that will take a player_id, find all distinct ip addresses logged for that person, and pull a list of distinct other player_ids that share each ip.
Example schema:
CREATE TABLE IF NOT EXISTS `ips` (
`ip_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ip` int(10) unsigned NOT NULL,
PRIMARY KEY (`ip_id`)
);
CREATE TABLE IF NOT EXISTS `joins` (
`join_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`player_id` int(10) unsigned NOT NULL,
`ip_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`join_id`)
);
The ips table records every unique ip I see, a players table records each unique player (not important for this) and the joins table records each time they connect.
Doing this with two queries was my first idea, and that works and is speedy - but I'd really like to make this work with a single query. I tried a query that uses a subquery but that takes forever to complete.
What's the most efficient way to query for this?

How does this work for you? http://sqlfiddle.com/#!2/133c6/1
SELECT DISTINCT
joins2.player_id,
ips.ip
FROM joins
JOIN ips
ON ips.ip_id = joins.ip_id
JOIN joins AS joins2
ON joins2.ip_id = ips.ip_id
AND joins2.player_id != #player_id
WHERE joins.player_id = #player_id

Related

Multiple indexing in a table mysql

I have a table structure like this
`CREATE TABLE `like_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sender_id` int(11) NOT NULL,
`receiver_id` int(11) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `index_user` (`sender_id`,`receiver_id`))`
I have indexed both sender_id and receiver_id. If I try to query this
`Select * from like_user where sender_id = 10`
The index works fine but on the other way around it doesn't.
`Select * from like_user where receiver_id = 11`
How can I make the index work on both the conditions.
The use case is that sender_id is the one who is liking a user and the person who sender id is liking is stored in receiver_id. So If sender wants to see all the users he likes, then indexing works, but if the receiver_id wants to see which senders have liked him, indexing stops working. how we can resolve it?
Only prefix can be used. Postfix cannot. I think that two separate indices, one by sender and another by receiver, will be reasonable:
CREATE TABLE `like_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`sender_id` int(11) NOT NULL,
`receiver_id` int(11) NOT NULL,
`created` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY (`sender_id`),
KEY (`receiver_id`)
);
One of these indices will be used for each table copy. For example, for
SELECT *
FROM like_user t1
JOIN like_user t2 ON t1.sender_id = t2.receiver_id;
the first table copy (t1) will use KEY (`sender_id`) whereas another table copy will use KEY (`receiver_id`).

Mysql limit joined table results by previous table column

I have three tables: test_composite, tests, questions. TestComposite belongs to Test. Test has many Questions.
create table test_composite
(
id bigint unsigned auto_increment
primary key,
id_include_test bigint unsigned not null,
questions_quantity smallint unsigned not null,
)
create table tests
(
id bigint unsigned auto_increment
primary key,
name varchar(128) not null,
)
create table questions
(
id bigint unsigned auto_increment
primary key,
question text not null,
test_id bigint unsigned not null,
)
The question is how to make this query work:
select questions.*
from test_composite
inner join tests on test_composite.id_include_test = tests.id
inner join questions on questions.id in (
select id
from questions
where tests.id = questions.test_id limit test_composite.questions_quantity
);
This query is expected to join test_composite and tests tables and then join questions with limit scope. Therefore everything comes to using previous table data in current table query.
Problem is that limit test_composite.questions_quantity isn't allowed.
Is there any way to do it?
PS. Mysql version 5.6.
I know a little about lateral join, but it is not supported in 5.6 version.

Mysql Very Slow Performance Using Order by Clause

I have a one table with millions of entry.Below is table structure.
CREATE TABLE `useractivity` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`userid` bigint(20) NOT NULL,
`likes` bigint(20) DEFAULT NULL,
`views` bigint(20) DEFAULT NULL,
`shares` bigint(20) DEFAULT NULL,
`totalcount` bigint(20) DEFAULT NULL,
`status` bigint(20) DEFAULT NULL,
`createdat` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `userid` (`userid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
And Below is query in which i am getting slow performance.
SELECT userid,
(sum(likes)+SUM(views)+SUM(shares)+SUM(totalcount)+SUM(`status`)) as total
from useractivity
GROUP BY userid
ORDER BY total DESC
limit 0, 20;
When i am executing above query without ORDER BY then it gives me fast result set But when using ORDER BY then this query became slow,though i used limit for pagination.
What can I do to speed up this query?
You can't speed up the query as it is, MySQL needs to visit every single row and calculate the sum before sorting and finally returning the first rows. That is bound to take time. You can probably cheat though.
The most obvious approach would be to create a summary table with userid and total. Update it when the base table changes or recompute it regularly, whatever makes sense. In that table you can index total, which makes the query trivial.
Another option may be to find the top users. Most sites have users that are more active than the others. Keep the 1000 top users in a separate table, then use the same select but only for the top users (i.e. join with that table). Only the useractivity rows for the top users need to be visited, which should be fast. If 1000 users are not enough perhaps 10000 works.

Longest MySQL queries for worst case testing

I have a big mysql Database (planned is about one million entries) and I want to test its performance by creating a worst query (longest calculation time) i am able to.
For now it is a database with two tables:
CREATE TABLE user (ID BIGINT NOT NULL AUTO_INCREMENT,
createdAt DATETIME NULL DEFAULT NULL,
lastAction DATETIME NULL DEFAULT NULL,
ip TEXT NULL DEFAULT NULL,
browser TEXT NULL DEFAULT NULL,
PRIMARY KEY (ID))
CREATE TABLE evt (ID BIGINT AUTO_INCREMENT,
UID BIGINT NULL DEFAULT NULL,
timeStamp DATETIME NULL DEFAULT NULL,
name TEXT NULL DEFAULT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (UID)
REFERENCES user(ID))
It's populated and is running locally so no connection is required.
Are there any rules of Thumb on how to create horrible queries?
My worst query for now was:
SELECT user.browser, evt.name, count(*) as AmountOfActions
FROM evt
JOIN user ON evt.UID = user.ID
GROUP BY user.browser, evt.name
ORDER BY AmountOfActions DESC
The number one cost in a query is disk hits. So, make a table big enough so that it cannot be cached in RAM. And/or do a cross-join (etc) such that an intermediate table is too big to be cached in RAM.
A common problem on this forum is lots of joins followed by a group by. Or lots of joins, plus an order by on the big intermediate result.
Here's a double-whammy -- join two tables (each too big to be cached) on a UUID.

MYSQL multiple joins with reference table

I have researched tirelessly to try and understand mysql joins with multiple tables and how reference tables come into play but to no avail. Also this is my first post so be gentle if I missed any rules.
Here are my tables:
customers | CREATE TABLE `customers` (
`customer_num` int(11) NOT NULL AUTO_INCREMENT,
`customer_name` varchar(50) DEFAULT NULL,
`city` varchar(50) DEFAULT NULL,
`state` varchar(50) DEFAULT NULL,
`country` varchar(50) DEFAULT NULL,
PRIMARY KEY (`customer_num`)
orders | CREATE TABLE `orders` (
`order_num` int(11) NOT NULL AUTO_INCREMENT,
`order_date` date DEFAULT NULL,
`shipped_date` date DEFAULT NULL,
`status` varchar(15) DEFAULT NULL,
`comments` text,
`customer_num` int(11) DEFAULT NULL,
PRIMARY KEY (`order_num`)
p_o | CREATE TABLE `p_o` (
`product_num` int(10) unsigned NOT NULL,
`order_num` int(10) unsigned NOT NULL,
KEY `order_num` (`order_num`)
products | CREATE TABLE `products` (
`product_num` int(11) NOT NULL AUTO_INCREMENT,
`year` int(4) unsigned NOT NULL DEFAULT '2014',
`make` varchar(20) NOT NULL,
`model` varchar(20) NOT NULL,
`price` int(6) NOT NULL DEFAULT '0',
PRIMARY KEY (`product_num`)
Customers has a one-many relationship with orders, while orders references to p_o which has both product_num and order_num, and p_o also connects to products.
My goal is to make a query (that is somewhat optimal, not all selects and wheres) that will show all of this information in one table. I created this but cannot get them to show more than just two tables information.
select * from customers t1 join orders t2 on t1.customer_num=t2.customer_num;
That join shows all of the information from orders and customers, and I intend on it being inner join. I've tried all sorts of ways to get them all to join into one but none of them work, and I do believe it's on my end. Also I'm using a module that makes dynamic mysql tables and doesn't support union, but even if you have a solution that uses union I will take it.
Any help you can offer is greatly appreciated, I've been working on this for far too many hours.
I think you should get the information needed using the following:
SELECT
`orders`.`order_num`,
`orders`.`order_date`,
`orders`.`shipped_date`,
`orders`.`status`,
`orders`.`comments`,
`orders`.`customer_num`,
`customers`.`customer_name`,
`customers`.`city`,
`customers`.`state`,
`customers`.`country`,
`products`.`product_num`,
`products`.`year`,
`products`.`make`,
`products`.`model`,
`products`.`price`
FROM
`orders`
inner join `customers`
ON `customers`.`customer_num` = `orders`.`customer_num`
inner join `p_o`
ON `p_o`.`order_num` = `orders`.`order_num`
inner join `products`
ON `products`.`product_num` = `p_o`.`product_num`
I'd like (and I hope) to help you understand the process of multiple join basing on this problem.
The in-words description of this multiple join operation could be like this:
I need to extract detailed information about orders i.e.: order header info, order customer detailed info and products ordered within each of the order numbers.
According to my database structure I can see that every order header from orders table has field with customer number whom the order belongs to, so I want to connect the detailed data from customers table to every order from orders table.
Then I know that I will also need the detailed specification of each product for every specific order.
My DB structure says that I can access product detailed information from products table through "connection" table p_othen I'm connecting p_o to my already-joined set {customers, orders} basing on the order_num column.
Having this information in the result set by now ({customers, orders, p_o}) I only need to connect products table to the p_o table on the product_code key.
In the end I list the columns needed from final result set consisting from four tables {customers, orders, p_o, products}.
I hope it could help you some way.