Putting clustered index on a join used column vs heavily scanned column? - sql-server

I have this simple table :
Table Users
userId | name
---------------------
1 'a1'
2 'a2'
3 'a3'
4 'a4'
5 'a5'
Table Cities
cityId | name
---------------------
1 'c1'
2 'c2'
3 'c3'
4 'c4'
5 'c5'
Each user is can be in more than one city. :
So the mapping table is :
userId | CityId
------------------------------------
1 4
1 4
1 4
2 5
5 6
Table users is heavily scanned by name .
Question :
For the mapping table I have no issues. both columns together are primary/clustered index.
But i'm struggling with myself about the first 2 tables :
I think that Users should have userId column as primary key. why ? because it is used throug the join to the mapping table.
but I also need clustered index on the name column cause this table is heavily scanned by name.
(leave aside the unique problem. lets say all columns are unique)
What is the best practice decision for this case ?

The best decision depends on how exactly you use the data returned by a query.
A clustered index means that the data in the page files are ordered based on this index.
A regular index will have it's own page files to order the index and a pointer to the physical row.
Thus a clustered index will serve better for theses queries that return a range of value instead of unique rows.
So, unless you do a lot of queries with like operations on the Name column, you would be better to keep your clustered index on the ID column, for this index will be constantly scanned and used to return recordsets to support your join operations.

Related

Why sort on sorted non clustered index field?

Say I have a table with ID, Name, and Date.
And I have a non-clustered index like,
CREATE NONCLUSTERED INDEX IX_Test_NameDate ON [dbo].[Test] (Name, Date)
When I run the query,
select
[Name], [Date]
from
[dbo].[Test] WITH (INDEX(IX_Test_NameDate))
where
[Name] like 'A%'
order by
[Date] asc
I get in SQL Server's execution plan,
Select <-- Sort <-- Index Seek (NonClustered)
Why the sort? Isn't the date already sorted in the non-clustered index? What would a better non-clustered index look like that doesn't require a sort (only an index seek).
(Can't use a clustered index as this example is a condensed version of a bigger example with multiple rows/indexes).
For example, I get the execution plan (with sort) for a table that looks like this,
ID Name Date
1 A 2014-01-01
2 A 2014-02-01
3 A 2014-03-01
4 A 2014-04-01
5 B 2014-01-01
6 B 2014-02-01
7 B 2014-03-01
8 B 2014-04-01
9 B 2014-05-01
10 B 2014-06-01
Shouldn't the dates be sorted in this case?
No, the Date column is not "already sorted in the non-clustered index", at least, not by itself. It is sorted after Name.
Consider the following trivial table data:
Name Date
----- --------
Allen 1/1/2014
Barb 1/1/2013
Charlie 1/1/2015
Darlene 1/1/2012
Ernie 1/1/2016
Faith 1/1/2011
Once you've sorted by Name, the Date columns are potentially out of order. Dates are guaranteed in order only for rows that have the same Name.
Your goals are at cross-purposes to each other. You want multiple names--so the data is best ordered by name so that the seek is possible, but then you want to sort by Date. How would you propose storing the above six-row table so that it is sorted by Date for every possible range of names?
If there is some kind of regularity or pattern about the ranges of names (perhaps, for example, you always pull names by first letter only) then there is a possible workaround.
ALTER TABLE dbo.Test ADD NamePrefix AS (Left(Name, 1)) PERSISTED;
CREATE NONCLUSTERED INDEX IX_Test_NamePrefix_Date ON dbo.Test (NamePrefix, Date);
Now this query theoretically should not need to perform the sort:
SELECT Name, Date
FROM dbo.Test
WHERE NamePrefix = 'A'
ORDER BY Date;
Be aware that there are some likely gotchas with adding a persisted computed column like this: increased data size, the fact that such a design is almost certainly wrong in almost every case, that the proliferation of computed columns would be very bad, among others.
P.S. It is generally not best practice to force indexes manually--let the optimizer choose.

how Unique key works on multiple columns

i have a table T with following columns
col1 col2 col3 col4
1 1 1 1
1 1 1 2
1 1 2 1
1 1 2 1
if i set a column col2,col3,col4 as unique. how does the unique works ? will it take uniqueness of combination of each column?
See here: http://www.w3schools.com/sql/sql_unique.asp
The syntax for setting multiple columns as unique is different from that of setting one column unique. If you have multiple columns as unique it is the set that is viewed for uniqueness.
Yes, the "unique-ness" is a result of all columns involved in the constraint. See SO Question
You can easily write yourself a table and test how it handles INSERTs
I'm not entirely sure, but I think the unique attribute has to do with indexing the table. Whichever column you set as unique, that column should be the one you call on to find a certain row. For example in a call like
UPDATE table_name SET column_name = some_value WHERE ID = some_number
the ID column should be set to unique, though I don't know whether not doing so would actually stop you from finding a specific row.

Programming Logic in Storing Multiple table ids in one table

I have Five Tables as Below
1.tblFruits
2.tblGroceries
3.tblVegetables
4.tblPlants
5.tblDescriptions
All the tables except 5th one tblDescriptions will have ids as one column and as primary key and Items as Second Column.
The column in table 1 to table 4 are similar and as follows
ids item_name
Now i want to store description of the items of the four table in the fifth table as below
Desc_Id Description Ids
Now the problem is since i am storing the ids to identify the description of the items in the other four table i might get similar ids when i put ids of four table together.
Let me know the table design for the above requirement
tblDescription
=====================
id | pk_id | description | type
id : auto_generated id of tblDescription
pk_id : foreign key to linked to the tblFruits,tblGroceries.. table
description : the description
type : value either be fruits, groceries,vegetables,plants .To identify the table.
SQL to extract description would be as below:
Select f.item_name, d.description from tblDescription d
inner join tblFruits f on d.pk_id=f.id and d.type='fruits'
inner join tblGroceries g on d.pk_id=g.id and d.type='groceries'
Use Polymorphic Association. As foreign key of your 5th table with description use two columns object_id and object_model.
Example of table content:
Desc_Id Description Object_ID Object_Model
1 'dsferer' 12 `Fruit`
2 `desc2 12 `Vegetable`
2 `descfdfd2 19 `Vegetable`
Remember to add unique index on both columns for performance reasons.
Here you have some article explaining this in PHP
As your tables are similar, the best practice is to combine all of your tables and even description and define row type using a type column.
id name description type
[Fruits, Groceries, Vegetables, Plants]
It's easier to understand and maintain.
But if your tables are different you have two option:
1- use a super table for your types which produce unique IDs which I suggest.
2- use a type row in your description field and define it as primary key beside ID in that table.

Sql Server 2008 unique columns by condition

Let's assume I have following table in the database:
Id ProductId ColorId IsDeleted
1 1 1 1
2 1 1 0
3 2 3 0
I want to make ProductId and ColorId columns unique but only for those rows where IsDeleted = 0. How do I can achieve this requirement?
I know, I can create a constraint which will call a stored function. And stored function will try to find an entry with the same values. But I think it is to complex way. May be there is a better decision...
In SQL Server 2008 and newer, you can take advantage of filtered indices to achieve this:
CREATE NONCLUSTERED UNIQUE INDEX ProductColor
ON dbo.YourTable(ProductID, ColorID)
WHERE IsDeleted = 0;
See the Filtered Index Design Guidelines for some more background and best practices.

MS Access Relationship help needed

I have 2 MS Access Tables.
Table 1
id
room-name
Table 2
wall
cupboard
ceiling
Now... table1.room-name has the room names and table2 contains object (many) so each room name contains many objects.
My question is ... How do I set the relationships for this please?
Nothing in table 2 tells you what room things are in so you need to add a foreign key of the room to the primary key of table 1. In this case either column of table1 could be its primary key - I would use room- name and drop the id.
So table2 needs altering so that room-name is in it and the draw the connection from table1 to table2.
Something like:
[Room]
RoomId eg 1 2
RoomName eg bedroom kitchen
[RoomItem]
RoomItemId eg 1 eg 2 eg 3
RoomId eg 1 eg 1 eg 2
ItemName eg wardrobe eg bed eg cooker
Where the RoomId links the Room and RoomItem tables.

Resources