I have two databases I need to work with, db_site and db_forum (these are generic names, FYI).
db_site has a table called main-news, which has a forumurl field which holds a forum thread id and a views field which holds the current pageviews for the article entry in the database. db_forum has a table called forum_threads which has a tid field and a replies field.
I have two things I need to do, one using just the replies and another using the replies and the views. I assume once the former is figured out the latter won't be much more than adding some extra parts, so I'm concerned with the former for the time being.
Not sure how I should approach this since the two tables are in different databases. The login I'm using has access to both of them (AFAIK), so that isn't the problem, it's more of the syntax involved. Would what I'm looking to do be something like this, perhaps?
SELECT
db_forum.forum_threads.replies AS replies
FROM
`db_forum.forum_threads` AS f,
`db_site.main-news` AS s
WHERE
f.tid = s.forumurl
That's a rough guess, from what I can find online abut doing this type of query. Any help is appreciated. :)
First of all, you should indent your SQL code properly. That long line was almost unreadable.
SELECT
db_forum.forum_threads.replies AS replies
FROM
`db_forum.forum_threads` AS f,
`db_site.main-news` AS s
WHERE
f.tid = s.forumurl
Then, make use of your table aliases "f" and "s". You introduced them, so you have to use them:
SELECT
f.replies AS replies
FROM
`db_forum.forum_threads` AS f,
`db_site.main-news` AS s
WHERE
f.tid = s.forumurl
Finally, you should remove the unnecessary quoting:
SELECT
f.replies AS replies
FROM
db_forum.forum_threads AS f,
db_site.main-news AS s
WHERE
f.tid = s.forumurl
If the names of the fields are indicative of their function, then f.tid refers to an identity column while s.forumurl does not. Normally the s.formurl in this case would be a foreign key. Just a guess.
Related
I'm working on an existing application that uses some JOIN statements to create "immutable" objects (i.e. the results are always JOINed to create a processable object - results from only one table will be meaningless).
For example:
SELECT r.*,u.user_username,u.user_pic FROM articles r INNER JOIN users u ON u.user_id=r.article_author WHERE ...
will yield a result of type, let's say, ArticleWithUser that is necessary to display an article with the author details (like a blog post).
Now, I need to make a table featured_items which contains the columnsitem_type (article, file, comment, etc.) and item_id (the article's, file's or comment's id), and query it to get a list of the featured items of some type.
Assuming tables other than articles contain whole objects that do not need JOINing with other tables, I can simply pull them with a dynamicially generated query like
SELECT some_table.* FROM featured_items RIGHT JOIN some_table ON some_table.id = featured_items.item_id WHERE featured_items.type = X
But what if I need to get a featured item from the aforementioned type ArticleWithUser? I cannot use the dynamically generated query because the syntax will not suit two JOINs.
So, my question is: is there a better practice to retrieve results that are always combined together? Maybe do the second JOIN on the application end?
Or do I have to write special code for each of those combined results types?
Thank you!
a view can be thot of as like a table for the faint of heart.
https://dev.mysql.com/doc/refman/5.0/en/create-view.html
views can incorporate joins. and other views. keep in mind that upon creation, they take a snapshot of the columns in existence at that time on underlying tables, so Alter Table stmts adding columns to those tables are not picked up in select *.
An old article which I consider required reading on the subject of MySQL Views:
By Peter Zaitsev
To answer your question as to whether they are widely used, they are a major part of the database developer's toolkit, and in some situations offer significant benefits, which have more to do with indexing than with the nature of views, per se.
I am setting up a MySQL database with multiple tables. Several of the tables will have fields with similar names that aren't necessarily for the same purpose.
For example, there's a users table that will have a name field, a category table with a name field and so on.
I've previously seen this setup up either with or without a preface to the field name, so in the above example using user_name, cat_name etc.
As these are all in separate tables, is there any benefit to structuring the database with or without this preface? I know that when using joins and calling the data through PHP you have to add a SELECT users.name AS username... to keep the fields from overwriting each other when using mysql_fetch_array. But i'm not sure if there's any efficiencies in using one method over the other?
It depends on what your shop does or your preference. There is nothing about a prefix that will make this better. Personally I would just keep it as name since: Users.Name and Orders.Name and Products.Name all contain tuples with different object types.
At the end of the day you want to be consistent. If you prefer a cat_ and a user_ prefix just be consistent with your design and include this prefix for all object types. To me less is more.
It's really just a matter of preference. I personally prefer the approach of using just name.
One thing to watch out for though, if you're doing any SELECT * FROM ... queries (which you shouldn't be; always select fields explicitly), you may end up selecting the wrong data.
One disadvantage is if anyone is stupid enough to use natural joins (you can guess that I find this a poor practice but mysql does allow it so you need to consider if that will happen) you may end up joining on those fields with the same name by accident.
Currently, I have a log file of messages in one table in a MySQL database. Among some other stuff, it contains the sender id, and the message itself. I want to make a way to display the log on a website.
I have a separate table that contains the sender ids and the name of the person (which is what I actually want to display).
Are there any better ways than simply running another query? While that would work, that's pretty expensive as it requires a new query for every entry. Ideally, I'd like something that would map the id --> name in an array, but I can only find things that will put everything from one row into an array (aka, horizontally), but I need entries "vertically".
I'm using PHP by the way...
Thanks!
Kevin
Learn about JOIN statements. This is exactly what you need.
I believe you are looking for something like this:
SELECT `name`, `message` FROM `msgtable` INNER JOIN `sendertable` USING(`sender_id`)
I know i am writing query's wrong and when we get a lot of traffic, our database gets hit HARD and the page slows to a grind...
I think I need to write queries based on CREATE VIEW from the last 30 days from the CURDATE ?? But not sure where to begin or if this will be MORE efficient query for the database?
Anyways, here is a sample query I have written..
$query_Recordset6 = "SELECT `date`, title, category, url, comments
FROM cute_news
WHERE category LIKE '%45%'
ORDER BY `date` DESC";
Any help or suggestions would be great! I have about 11 queries like this, but I am confident if I could get help on one of these, then I can implement them to the rest!!
Putting a wildcard on the left side of a value comparison:
LIKE '%xyz'
...means that an index can not be used, even if one exists. Might want to consider using Full Text Searching (FTS), which means adding full text indexing.
Normalizing the data would be another step to consider - categories should likely be in a separate table.
SELECT `date`, title, category, url, comments
FROM cute_news
WHERE category LIKE '%45%'
ORDER BY `date` DESC
The LIKE '%45%' means a full table scan will need to be performed. Are you perhaps storing a list of categories in the column? If so creating a new table storing category and news_article_id will allow an index to be used to retrieve the matching records much more efficiently.
OK, time for psychic debugging.
In my mind's eye, I see that query performance would be improved considerably through database normalization, specifically by splitting the category multi-valued column into a a separate table that has two columns: the primary key for cute_news and the category ID.
This would also allow you to directly link said table to the categories table without having to parse it first.
Or, as Chris Date said: "Every row-and-column intersection contains exactly one value from the applicable domain (and nothing else)."
Anything with LIKE '%XXX%' is going to be slow. Its a slow operation.
For something like categories, you might want to separate categories out into another table and use a foreign key in the cute_news table. That way you can have category_id, and use that in the query which will be MUCH faster.
Also, I'm not quite sure why you're talking about using CREATE VIEW. Views will not really help you for speed. Not unless its a materialized view, which MySQL doesn't suppose natively.
If your database is getting hit hard, the solution isn't to make a view (the view is still basically the same amount of work for the database to do), the solution is to cache the results.
This is especially applicable since, from what it sounds like, your data only needs to be refreshed once every 30 days.
I'd guess that your category column is a list of category values like "12,34,45,78" ?
This is not good relational database design. One reason it's not good is as you've discovered: it's incredibly slow to search for a substring that might appear in the middle of that list.
Some people have suggested using fulltext search instead of the LIKE predicate with wildcards, but in this case it's simpler to create another table so you can list one category value per row, with a reference back to your cute_news table:
CREATE TABLE cute_news_category (
news_id INT NOT NULL,
category INT NOT NULL,
PRIMARY KEY (news_id, category),
FOREIGN KEY (news_id) REFERENCES cute_news(news_id)
) ENGINE=InnoDB;
Then you can query and it'll go a lot faster:
SELECT n.`date`, n.title, c.category, n.url, n.comments
FROM cute_news n
JOIN cute_news_category c ON (n.news_id = c.news_id)
WHERE c.category = 45
ORDER BY n.`date` DESC
Any answer is a guess, show:
- the relevant SHOW CREATE TABLE outputs
- the EXPLAIN output from your common queries.
And Bill Karwin's comment certainly applies.
After all this & optimizing, sampling the data into a table with only the last 30 days could still be desired, in which case you're better of running a daily cronjob to do just that.
Maybe it's a little dumb, but i'm just not sure what is better.
If i have to check more than 10k rows in db for existanse, what i'd do?
#1 - one query
select id from table1 where name in (smth1,smth2...{till 30k})
#2 - many queries
select id from table1 where name=smth1
Though, perfomance is not the goal, i don't want to go down with mysql either ;)
Maybe, any other solutions will be more suitable...
Thanks.
upd: The task is to fetch domains list, save new (that are not in db yet) and delete those that dissappeared from list. Hope, it'll help a little...
What you should do is create a temp table, insert all of the names, and (using one query) join against this table for your select.
select id
from table1 t1
inner join temptable tt on t1.name = tt.name
The single query will most likely perform better as the second will give a lot of round-trip delays. But if you have a lot of names like in your example the first method might cause you to hit an internal limit.
In this case it might be better to store the list of names in a temporary table and join with it.
Depending on your future needs to do similar things, you might want to add a function in the database 'strlist_to_table'. Let the function take a text where your input is delimited by a delimiter character (possibly also passed to function), split it on the delimiter to create a on-the-fly table. Then you can use
where in strlist_to_table('smth1|smth2', '|')
and also get protection from sql injection (maybe little Bobby Tables appears in the input).
Just my 2 cents...
I'm not sure how flexible your application design is, but it might be worth looking into removing the delimited list altogether and simply making a permanent third table to represent the many-to-many relationship, then joining the tables on each query.