SQL Server - Determining Missing Indexes - DMVs - sql-server

I am using the following query to determine missing indexes:
select
db_name(d.database_id) as DatabaseName,
object_name(d.object_id) TableName,
d.index_handle as IndexHandle,
d.equality_columns as EqualityColumns,
d.inequality_columns as InequalityColumns,
d.included_columns as IncludedColumns,
d.statement as Object,
gs.user_seeks as PossibleUserSeeks,
gs.user_scans as PossibleUserScans,
gs.last_user_seek as LastPossibleUserSeek,
gs.last_user_scan as LastPossibleUserScan,
gs.system_seeks as PossibleSystemSeeks,
gs.system_scans as PossibleSystemScans
from
sys.dm_db_missing_index_groups g
join sys.dm_db_missing_index_group_stats gs on gs.group_handle = g.index_group_handle
join sys.dm_db_missing_index_details d on g.index_handle = d.index_handle
where
d.database_id = d.database_id and
d.object_id = d.object_id And
DB_NAME(d.database_id) = 'MESProduction'
My question concerns 'd.index_handle'. MSDN describes this column as follows: Identifies a particular missing index. The identifier is unique across the server. index_handle is the key of this table. If the index is missing, how can it be identified? And what does it mean when it says, "is the key of this table"?
Thanks very much.

Related

SQL Server Index over lookup table of distinct values

I am trying to speed up the following SQL Server query:
SELECT
V.Id, V.Number, V.VisitDate, V.ArrivalTime, V.VisitKindId, VK.Description AS
VisitKindDescription,
VK.DescriptionAr AS VisitKindDescriptionAr, V.StatusId, V.Note, V.CancelingReason,
V.CancelingTime, V.EnterToDoctorRoomTime,
V.PatientId, P.Number AS PatientNumber, P.FirstName, P.LastName, P.BirthDate, P.Note AS
PatientNotes, V.DoctorId, D.FullName AS DoctorFullName, V.CreatedById,
U.FullName AS UserFullName, V.CreationDate, V.VersionNo
FROM
Patient_Tbl P INNER JOIN
Visit_Tbl V ON P.Id = V.PatientId INNER JOIN
VisitKind_Tbl VK ON V.VisitKindId = VK.Id INNER JOIN
Doctor_Tbl D ON V.DoctorId = D.Id INNER JOIN
User_Tbl U ON V.CreatedById = U.Id INNER JOIN
VisitStatus_Tbl VS ON V.StatusId = VS.Id
WHERE V.StatusId = 2 --patient is in doctor room
and we had the following 4 values the VisitStatus_Tbl:
(1 -> In Waiting Room, 2 -> In Doctor Room, 3 -> Canceled, 4 -> Completed)
and in one moment of time, there is only one record on the Visits table for one person in the doctor's room.
The end-user inform me that there is a delay in the use case that depends on the above query.
Please help us speed system performance by suggesting the proper index.
Thanks,
You do not indicate if you have any indexes on the tables now. I will assume that the 'ID' columns for patient_tbl, etc are clustered primary keys or just primary keys and have indexes. If not, that is another problem.
Simple rule: start with index foreign keys (lookup tables) and WHERE clauses.
CREATE INDEX ix_visit_tbl_statusid ON visit_tbl(statusId)
CREATE INDEX ix_visit_tbl_patientid ON visit_tbl(patientId)
CREATE INDEX ix_visit_tbl_visitkindId ON visit_tbl(visitkindId)
CREATE INDEX ix_visit_tbl_doctorid ON visit_tbl(doctorId)
CREATE INDEX ix_visit_tbl_createdbyid ON visit_tbl(createdbyId)
Now for the comments on how that is too many indexes. It depends ...

Why do I have duplicate records in my JOIN

I am retrieving data from table ProductionReportMetrics where I have column NetRate_QuoteID. Then to that result set I need to get Description column.
And in order to get a Description column, I need to join 3 tables:
NetRate_Quote_Insur_Quote
NetRate_Quote_Insur_Quote_Locat
NetRate_Quote_Insur_Quote_Locat_Liabi
But after that my premium is completely off.
What am I doing wrong here?
SELECT QLL.Description,
QLL.ClassCode,
prm.NetRate_QuoteID,
QL.LocationID,
ISNULL(SUM(premium),0) AS NetWrittenPremium,
MONTH(prm.EffectiveDate) AS EffMonth
FROM ProductionReportMetrics prm
LEFT JOIN NetRate_Quote_Insur_Quote Q
ON prm.NetRate_QuoteID = Q.QuoteID
INNER JOIN NetRate_Quote_Insur_Quote_Locat QL
ON Q.QuoteID = QL.QuoteID
INNER JOIN NetRate_Quote_Insur_Quote_Locat_Liabi QLL
ON QL.LocationID = QLL.LocationID
WHERE YEAR(prm.EffectiveDate) = 2016 AND
CompanyLine = 'Ironshore Insurance Company'
GROUP BY MONTH(prm.EffectiveDate),
QLL.Description,
QLL.ClassCode,
prm.NetRate_QuoteID,
QL.LocationID
I think the problem in this table:
What Am I missing in this Query?
select
ClassCode,
QLL.Description,
sum(Premium)
from ProductionReportMetrics prm
LEFT JOIN NetRate_Quote_Insur_Quote Q ON prm.NetRate_QuoteID = Q.QuoteID
LEFT JOIN NetRate_Quote_Insur_Quote_Locat QL ON Q.QuoteID = QL.QuoteID
LEFT JOIN
(SELECT * FROM NetRate_Quote_Insur_Quote_Locat_Liabi nqI
JOIN ( SELECT LocationID, MAX(ClassCode)
FROM NetRate_Quote_Insur_Quote_Locat_Liabi GROUP BY LocationID ) nqA
ON nqA.LocationID = nqI.LocationID ) QLL ON QLL.LocationID = QL.LocationID
where Year(prm.EffectiveDate) = 2016 AND CompanyLine = 'Ironshore Insurance Company'
GROUP BY Q.QuoteID,QL.QuoteID,QL.LocationID
Now it says
Msg 8156, Level 16, State 1, Line 14
The column 'LocationID' was specified multiple times for 'QLL'.
It looks like DVT basically hit on the answer. The only reason you would get different amounts(i.e. duplicated rows) as a result of a join is that one of the joined tables is not a 1:1 relationship with the primary table.
I would suggest you do a quick check against those tables, looking for table counts.
--this should be your baseline count
SELECT COUNT(*)
FROM ProductionReportMetrics
GROUP BY MONTH(prm.EffectiveDate),
prm.NetRate_QuoteID
--this will be a check against the first joined table.
SELECT COUNT(*)
FROM NetRate_Quote_Insur_Quote Q
WHERE QuoteID IN
(SELECT NetRate_QuoteID
FROM ProductionReportMetrics
GROUP BY MONTH(prm.EffectiveDate),
prm.NetRate_QuoteID)
Basically you will want to do a similar check against each of your joined tables. If any of the joined tables are part of the grouping statement, make sure they are also in the grouping of the count check statement. Also make sure to alter the WHERE clause of the check count statement to use the join clause columns you were using.
Once you find a table that returns the incorrect number of rows, you will have your answer as to what table is causing the problem. Then you will just have to decide how to limit that table down to distinct rows(some type of aggregation).
This advice is really just to show you how to QA this particular query. Break it up into the smallest possible parts. In this case, we know that it is a join that is causing the problem, so take it one join at a time until you find the offender.

oracle grammar to h2 grammar (+) join table

I have the following query as Oracle
SELECT DISTINCT count(pa.payment_id) FROM
location c, inventory e,
inventory_stock es, payment_client ep,
payment pa, currency cur,
location s, exchange_country exc,
exchange_rate sso,
exchange_hike so,
exchange_margin sov WHERE
cur.outState = 'N' AND
c.location_id = e.location_id AND
e.inventory_id = ep.inventory_id AND
e.inventory_stock_id = es.inventory_stock_id AND
ep.client_id = pa.end_client AND
pa.cur_id = cur.cur_id AND
cur.location_id = s.location_id AND
c.client_id is not null AND
cur.cur_id = exc.cur_id(+) AND
exc.exchange_id = sso.exchange_id(+) AND
sso.account_id = so.account_id(+) AND
so.option_name(+) = 'PREMIUM' AND
exc.exchange_id = sov.exchange_id(+) AND
sov.name(+) = 'VALUE';
Right now I am using H2 database and the syntax error I got was from so.option_name(+) and sov.name(+); I know the (+) are oracle's way of right join and left join but are there any possible way to convert this into h2 so the error and the grammar are equivalent?
It's time to move on. Oracle's legacy outer join syntax is no longer recommended by Oracle. From the docs:
Oracle recommends that you use the FROM clause OUTER JOIN syntax rather than the Oracle join operator. Outer join queries that use the Oracle join operator (+) are subject to the following rules and restrictions, which do not apply to the FROM clause OUTER JOIN syntax [...]
If you replace (+) usage by outer join, not only will your query work on both Oracle and H2, it will also be an important step forward for your application as a whole.
SELECT DISTINCT count(pa.payment_id)
FROM location c
JOIN inventory e ON c.location_id = e.location_id
JOIN payment_client ep ON e.inventory_id = ep.inventory_id
JOIN inventory_stock es ON e.inventory_stock_id = es.inventory_stock_id
JOIN payment pa ON ep.client_id = pa.end_client
JOIN currency cur ON pa.cur_id = cur.cur_id
JOIN location s ON cur.location_id = s.location_id
LEFT JOIN exchange_country exc ON cur.cur_id = exc.cur_id
LEFT JOIN exchange_rate sso ON exc.exchange_id = sso.exchange_id
LEFT JOIN exchange_hike so
ON sso.account_id = so.account_id
AND so.option_name = 'PREMIUM'
LEFT JOIN exchange_margin sov
ON exc.exchange_id = sov.exchange_id
AND sov.name = 'VALUE'
WHERE c.client_id IS NOT NULL
AND cur.outState = 'N'
The importance when converting from (+) to LEFT JOIN is that you pay close attention which predicates must go into an ON clause, and which predicates are fine in the WHERE clause. In particular, the following two predicates must go in the relevant left joined table's ON clause:
so.option_name(+) = 'PREMIUM'
sov.name(+) = 'VALUE'
Third party tooling
You can use jOOQ's online SQL translator to translate between the syntaxes, or use jOOQ directly to translate from table lists with Oracle joins to ansi joins.
Disclaimer: I work for the company behind jOOQ

Find columns with different types across supposedly equivalent databases

Each of our clients has a database with their own data. Each database should have exactly the same structure. How can I find columns whose datatype has been changed, where the table name and column name is the same but the datatype is not? Is there an SQL query that can do this?
Take snapshots of the schemas and use REDGATE's SQL Compare utility.
Or export the schemas to text and use BeyondCompare
If both databases can be restored to the same server, you can compare the two sets of system catalog views to determine the differences:
SELECT
TableName = t.name,
ColumnName = c.name,
TypeName = ty.name,
TableName2 = t2.name,
ColumnName2 = c2.name,
TypeName2 = ty2.name
FROM DB1.sys.columns c
INNER JOIN DB1.sys.tables t ON c.object_id = t.object_id
INNER JOIN DB1.sys.types ty ON c.system_type_id = ty.system_type_id
INNER JOIN DB2.sys.tables t2 ON t.name = t2.Name
INNER JOIN DB2.sys.columns c2 ON c2.object_id = t2.object_id AND c.name = c2.name
INNER JOIN DB2.sys.types ty2 ON c2.system_type_id = ty2.system_type_id
WHERE
c.system_type_id <> c2.system_type_id
Of course, you can add more columns from the sys.columns catalog view, e.g. precision and scale for types like DECIMAL(18,2), or max_length for string-based types (like VARCHAR(50) etc.) - adapt this base query as needed
The Atlantis SchemaInspector is good tool for this purpose.
EDIT:
If you want SQL query, you need the available both databases in one query.
So the databases must be on one sql server instance OR the sql server instances must are available as linked server.
Query:
SELECT
*
/* source database >>> */
FROM [SourceDatabase].[sys].[schemas] AS S_A
INNER JOIN [SourceDatabase].[sys].[objects] AS O_A
ON [O_A].[schema_id] = [S_A].[schema_id]
INNER JOIN [SourceDatabase].[sys].[columns] AS C_A
ON [C_A].[object_id] = [O_A].[object_id]
/* <<< source database */
/* target database >>> */
LEFT JOIN [TargetDatabase].[sys].[schemas] AS S_B
ON [S_B].[name] = [S_A].[name]
LEFT JOIN [TargetDatabase].[sys].[objects] AS O_B
ON [O_B].[schema_id] = [S_B].[schema_id]
AND [O_B].[name] = [O_A].[name]
LEFT JOIN [TargetDatabase].[sys].[columns] AS C_B
ON [C_B].[object_id] = [O_B].[object_id]
AND [C_B].[name] = [C_A].[name]
/* <<< target database */
WHERE [C_B].[column_id] IS NULL
OR [C_B].[system_type_id] <> [C_A].[system_type_id]

Constraints / Foreign keys information in Oracle

I have to get the Table and Column name of the Foreign keys on Oracle, can anybody confirm the following statement?
SELECT a.table_name AS TableWithForeignKey, b.column_name AS ForeignKeyColumn
FROM user_constraints a INNER JOIN user_cons_columns b
ON (a.constraint_name = b.constraint_name) AND (a.table_name = b.table_name)
and a.constraint_type = 'R'
The Part I'm not sure about is the INNER JOIN Part (after ON):
(a.constraint_name = b.constraint_name) AND (a.table_name = b.table_name)
As I couldn't find something like constraints_ID, is this enought to match 1:1 rows from both tables user_constraints and user_cons_columns
Thank you.
I use the
a.constraint_name = b.constraint_name
for joining the 2 views
so, I think it's OK

Resources