How can I increase speed of SQL query? - sql

As a Image that I sent ,
For getting count of comment can I add one filed in table of Module or not , my mean is for big record like 100 million comments or big project, which one is better/faster adding one filed to module and after each inserting comment update it or have a relationship
For getting count of comment , I must to choose which one :
select Module.Id,
(SELECT COUNT(*) AS Expr1
FROM dbo.CommentTable
WHERE (CommentTable.MuoduleId= Module.userid)) AS commentCount
from Model
or
select Module.Id, Module.CountComment

I suggest you compute it on the fly instead of saving the count in the table itself. To get the count of comments of each Module:
SELECT
m.id,
CommentCount = COUNT(c.ModuleId)
FROM Module m
LEFT JOIN CommentTable c
ON c.ModuleId = m.Id
GROUP BY m.id
This will be faster if you have an index on CommentTable(ModuleId):
CREATE NONCLUSTERED INDEX NCI_CommentTable_ModuleId ON CommentTable(ModuleId)

Related

Can we select data from 2 tables in same time

From the code as shown below. I wonder that why it can select data from 2 tables in same time that are table "venue AS v" and table "as s".
or I misunderstand?
SELECT name, s.num_match
FROM venue AS v,
(SELECT venue_id, COUNT(*) AS num_match
FROM match
GROUP BY venue_id) AS s
WHERE v.venue_id = s.venue_id
LIMIT 3;
Yes you can using JOIN clause for example.
More infos here: https://www.informit.com/articles/article.aspx?p=30875&seqNum=5
Yes you can select data from as many as tables you want at the same time.
In this case you are trying to get an aggregated number from table-s and join it with the table v.
There are many ways to write the code to join the table. Above is one method which you have used.

How I use where clause with computed column to get related records only

I read this FAQ http://www.firebirdfaq.org/faq289/ and I want to use select to count detail record from current record so I tried this
((
select count(*) from detail_table where detail_table.id = id
))
But I did not get correct values I got numbers like 19 where in fact it is the total number of records in detail_table! How can I get only the count of records related to current master record in master table?
The problem is that id refers to the id column of detail_table and not of the master table. So it is the equivalent of:
select count(*) from detail_table where detail_table.id = detail_table.id
Which means you are simply counting all rows. Instead - assuming the master table is master_table - you should use:
select count(*) from detail_table where detail_table.id = master_table.id
Note that, as also mentioned in the FAQ you link to, you should really consider using a view instead of a computed column when referencing other tables as it is not very good for performance.
The view equivalent would be something like
CREATE OR ALTER VIEW master_with_detail_count
AS
SELECT master_table.id, coalesce(c.detail_count, 0) as detail_count
FROM master_table
LEFT JOIN (SELECT id, count(*) as detail_count FROM detail GROUP BY id) c
ON c.id = master.id

Complex sql select

I can't figure out how to make this sql select statement...Here are my tables :
I opened the tables concerned by the request
So basically I want to select the number of albums for each interpret.
I just can't figure it out... I am currently thinking that I need to do my first select on album like :
select interpret.no_interpret, count(*)
from album
.
.
.
group by interpret.no_interpret;
and there work from this but I don't know where to go next.
I may be missing something, but I'm not seeing the direct relation from your song table to the album...
I would first start by getting the link_interpret_song table joined to the song table and get count of distinct albums. However, I didn't see what appears to be a "No_Album" column in the field list of the song table. I can only guess it IS in there associated to the particular album. I did see media, but to me, that would be like a TYPE of media (digital, download, vinyl, CD) vs the actual ID Key apparent to the album table.
That said, I am thinking there IS such a "No_Album" column in the SONG table.
select
LIS.No_Interpret,
COUNT( DISTINCT S.No_Album )
from
Link_Interpret_Song LIS
JOIN Song S
on LIS.No_Song = S.No_Song
group by
LIS.No_Interpret;
Now, that said, if you want the interpret details, take the above results and join that to the interpret table. I've done both distinct album count and total # of songs just as an example of count() vs count(distinct) context... such as
select
PreCounts.No_Interpret,
PreCounts.DistinctAlbums,
PreCounts.ActualSongs,
I.Name_Interpret,
I.First_Name,
I.Stage_Name
from
( select
LIS.No_Interpret,
COUNT( DISTINCT S.No_Album ) as DistinctAlbums,
COUNT(*) as ActualSongs
from
Link_Interpret_Song LIS
JOIN Song S
on LIS.No_Song = S.No_Song
group by
LIS.No_Interpret ) as PreCounts
JOIN Interpret I
ON PreCounts.No_Interpret = I.No_Interpret
The question is ambiguous since there isn't a clear indication of how the tables are related. Given assumptions about these relations, your query will likely take on something similar to the following form:
SELECT COUNT(distinct a.no_album) from album a, interpret i, song s
where i.no_song=s.no_song
and a.no_album=s.no_album GROUP BY i.no_interpret

MS Access Distinct Records in Recordset

So, I once again seem to have an issue with MS Access being finicky, although it seems to also be an issue when trying similar queries in SSMS (SQL Server Management Studio).
I have a collection of tables, loosely defined as follows:
table widget_mfg { id (int), name (nvarchar) }
table widget { id (int), name (nvarchar), mfg_id (int) }
table widget_component { id (int), name (nvarchar), widget_id (int), component_id }
table component { id (int), name (nvarchar), ... } -- There are ~25 columns in this table
What I'd like to do is query the database and get a list of all components that a specific manufacturer uses. I've tried some of these queries:
SELECT c.*, wc.widget_id, w.mfg_id
FROM ((widget_component wc INNER JOIN widget w ON wc.widget_id = w.id)
INNER JOIN widget_manufacturer wm on w.mfg_id = wm.id)
INNER JOIN component c on c.id = wc.component_id
WHERE wm.id = 1
The previous example displays duplicates of any part that is contained in multiple widget_component lists for different widgets.
I've also tried doing:
SELECT DISTINCT c.id, c.name, wc.widget_id, w.mfg_id
FROM component c, widget_component wc, widget w, widget_manufacturer wm
WHERE wm.id=w.mfg_id AND wm.id = 1
This doesn't display anything at all. I was reading about sub-queries, but I do not understand how they work or how they would apply to my current application.
Any assistance in this would be beneficial.
As an aside, I am not very good with either MS Access or SQL in general. I know the basics, but not a lot beyond that.
Edit:
I just tried this code, and it works to get all the component.id's while limiting them to a single entry each. How do I go about using the results of this to get a list of all the rest of the component data (component.*) where the id's from the first part are used to select this data?
SELECT DISTINCT c.part_no
FROM component c, widget w, widget_component wc, widget_manufacturer wm
WHERE(((c.id=wc.component_id AND wc.widget_id=w.id AND w.mfg_id=wm.id AND wm.id=1)))
(P.S. this is probably not the best way to do this, but I am still learning SQL.)
What I'd like to do is query the database and get a list of all
components that a specific manufacturer uses
There are several ways to do this. IN is probably the easiest to write
SELECT c.*
FROM component c
WHERE c.id IN (SELECT c.component_id
FROM widget w
INNER JOIN widget_component c
ON w.id = c.widget_id
WHERE w.mfg_id = 123)
The IN sub query finds all the component ids that a specific manufacturer uses. The outer query then selects any component.id that is that result. It doesn't matter if its in there once or 1000 times it will only get the component record once.
The other ways of doing this are using an EXISTS sub query or using a join to the query (but then you do need to de-dup it)
It sounds like your component -to- widget relationship is one-to-many. Hence the duplicates. (i.e., the same component is used by more than one widget).
Your Select is almost OK --
SELECT c.*, wc.widget_id, w.mfg_id
but the wc.widget_id is causing the duplicates (per the assumption above).
So remove wc.widget_id from the SELECT, or else aggregate it (min, max, count, etc.). Removing is easier. If you agregate, remember to add a group by clause.
Try this:
SELECT DISTINCT c.*, w.mfg_id
Also -- FWIW, it's generally a better practice to use field names, instead of the *

Aggregation with two Joins (MySQL)

I have one table called gallery. For each row in gallery there are several rows in the table picture. One picture belongs to one gallery. Then there is the table vote. There each row is an upvote or a downvote for a certain gallery.
Here is the (simplified) structure:
gallery ( gallery_id )
picture ( picture_id, picture_gallery_ref )
vote ( vote_id, vote_value, vote_gallery_ref )
Now I want one query to give me the following information: All galleries with their own data fields and the number of pictures that are connected to the gallery and the sumarized value of the votes.
Here is my query, but due to the multiple joining the aggregated values are not the right ones. (At least when there is more than one row of either pictures or votes.)
SELECT
*, SUM( vote_value ) as score, COUNT( picture_id ) AS pictures
FROM
gallery
LEFT JOIN
vote
ON gallery_id = vote_gallery_ref
LEFT JOIN
picture
ON gallery_id = picture_gallery_ref
GROUP BY gallery_id
Because I have noticed that COUNT( DISTINCT picture_id ) gives me the correct number of pictures I tried this:
( SUM( vote_value ) / GREATEST( COUNT( DISTINCT picture_id ), 1 ) ) AS score
It works in this example, but what if there were more joins in one query?
Just want to know whether there is a better or more 'elegant' way this problem can be solved. Also I'd like to know whether my solution is MySQL-specific or standard SQL?
This quote from William of Okham applies here:
Enita non sunt multiplicanda praeter necessitatem
(Latin for "entities are not to be multiplied beyond necessity").
You should reconsider why do you need this to be done in a single query? It's true that a single query has less overhead than multiple queries, but if the nature of that single query becomes too complex, both for you to develop, and for the RDBMS to execute, then run separate queries.
Or just use subqueries...
I don't know if this is valid MySQL syntax, but you might be able to do something similar to:
SELECT
gallery.*, a.score, b.pictures
LEFT JOIN
(
select vote_gallery_ref, sum(vote_value) as score
from vote
group by vote_gallery_ref
) a ON gallery_id = vote_gallery_ref
LEFT JOIN
(
select picture_gallery_ref, count(picture_id) as pictures
from picture
group by picture_gallery_ref
) b ON gallery_id = picture_gallery_ref
How often do you add/change vote records?
How often do you add/remove picture records?
How often do you run this query for these totals?
It might be better to create total fields on the gallery table (total_pictures, total_votes, total_vote_values).
When you add or remove a record on the picture table you also update the total on the gallery table. This could be done using triggers on the picture table to automatically update the gallery table. It could also be done using a transaction combining two SQL statements to update the picture table and the gallery table. When you add a record on the picture table increment the total_pictures field on the gallery table. When you delete a record on the picture table decrement the total_pictures field.
Similary when a vote record is added or removed or the vote_value changes you update the total_votes and total_vote_values fields. Adding a record increments the total_votes field and adds vote_values to total_vote_values. Deleting a record decrements the total_votes field and subtracts vote_values from total_vote_values. Updating vote_values on a vote record should also update total_vote_values with the difference (subtract old value, add new value).
Your query now becomes trivial - it's just a straightforward query from the gallery table. But this is at the expense of more complex updates to the picture and vote tables.
As Bill Karwin said, doing this all within one query is pretty ugly.
But, if you have to do it, joining and selecting non-aggregate data with aggregate data requires joining against subqueries (I haven't used SQL that much in the past few years so I actually forgot the proper term for this).
Let's assume your gallery table has additional fields name and state:
select g.gallery_id, g.name, g.state, i.num_pictures, j.sum_vote_values
from gallery g
inner join (
select g.gallery_id, count(p.picture_id) as 'num_pictures'
from gallery g
left join picture p on g.gallery_id = p.picture_gallery_ref
group by g.gallery_id) as i on g.gallery_id = i.gallery_id
left join (
select g.gallery_id, sum(v.vote_value) as 'sum_vote_values'
from gallery g
left join vote v on g.gallery_id = v.vote_gallery_ref
group by g.gallery_id
) as j on g.gallery_id = j.gallery_id
This will yield a result set that looks like:
gallery_id, name, state, num_pictures, sum_vote_values
1, 'Gallery A', 'NJ', 4, 19
2, 'Gallery B', 'NY', 3, 32
3, 'Empty gallery', 'CT', 0,