We're using .NET Entity Framework to talk to an Azure SQL database. We used QueryOriginInterceptor to add some comments to the top of each SQL command being sent to SQL Server, with the goal of helping identify the location where a particular query came from in the code.
The problem is, when looking at long running queries in the Azure UI (and looking in sys.dm_exec_query_stats), the comments are not there.
For example, if we run this query:
-- Stack:
-- Utils.Orders.GetOrders
select *
from [Order] o
join OrderItem oi on oi.OrderId = o.ID
And looking in Azure, the long running query looks like:
Is there a way to preserve these comments?
sys.dm_exec_query_stats does not include the comments, but dm_exec_sql_text does.
This artice explains how to use the two to diagnose issues.
The relevant SQL query from the article is:
SELECT TOP 25
databases.name,
dm_exec_sql_text.text AS TSQL_Text,
CAST(CAST(dm_exec_query_stats.total_worker_time AS DECIMAL)/CAST(dm_exec_query_stats.execution_count AS DECIMAL) AS INT) as cpu_per_execution,
CAST(CAST(dm_exec_query_stats.total_logical_reads AS DECIMAL)/CAST(dm_exec_query_stats.execution_count AS DECIMAL) AS INT) as logical_reads_per_execution,
CAST(CAST(dm_exec_query_stats.total_elapsed_time AS DECIMAL)/CAST(dm_exec_query_stats.execution_count AS DECIMAL) AS INT) as elapsed_time_per_execution,
dm_exec_query_stats.creation_time,
dm_exec_query_stats.execution_count,
dm_exec_query_stats.total_worker_time AS total_cpu_time,
dm_exec_query_stats.max_worker_time AS max_cpu_time,
dm_exec_query_stats.total_elapsed_time,
dm_exec_query_stats.max_elapsed_time,
dm_exec_query_stats.total_logical_reads,
dm_exec_query_stats.max_logical_reads,
dm_exec_query_stats.total_physical_reads,
dm_exec_query_stats.max_physical_reads,
dm_exec_query_plan.query_plan,
dm_exec_cached_plans.cacheobjtype,
dm_exec_cached_plans.objtype,
dm_exec_cached_plans.size_in_bytes
FROM sys.dm_exec_query_stats
CROSS APPLY sys.dm_exec_sql_text(dm_exec_query_stats.plan_handle)
CROSS APPLY sys.dm_exec_query_plan(dm_exec_query_stats.plan_handle)
INNER JOIN sys.databases
ON dm_exec_sql_text.dbid = databases.database_id
INNER JOIN sys.dm_exec_cached_plans
ON dm_exec_cached_plans.plan_handle = dm_exec_query_stats.plan_handle
WHERE databases.name = 'AdventureWorks2014'
ORDER BY dm_exec_query_stats.max_logical_reads DESC;
Related
I recently asked a question on StackOverflow (MySQL Returns All Rows When field = 0) regarding a query statement not working in MySQL. I now have a very similar problem, this time using OleDB where I am trying to use a join to include fields that have 0 as an entry, but not select every field in the table as a result.
The new look MySQL query posted in the above question as the accepted answer works without a hitch. However the OleDB counterpart I have written to do almost the same does not. It's a bit messy as the tables are not named very well (I didn't create this database) and I'm getting a simple syntax error;
myQuery.CommandText = "SELECT s.scm_num, s.scm_name, c.cr3_text, q.qsp_value, s.scm_bprefix, s.scm_nxbnum FROM qspreset q INNER JOIN sdccomp s LEFT OUTER JOIN cntref3 c ON s.scm_cntref3=c.cr3_id AND q.qsp_relat=s.scm_invtype AND q.qsp_what=13";
I'm querying another table here as well as the two involved in the LEFT OUTER JOIN and I believe that is where I am making the mistake.
Join conditions need to be with the join
myQuery.CommandText =
"SELECT s.scm_num, s.scm_name, c.cr3_text, q.qsp_value, s.scm_bprefix, s.scm_nxbnum
FROM qspreset q
INNER JOIN sdccomp s
on q.qsp_relat = s.scm_invtype AND q.qsp_what = 13
LEFT OUTER JOIN cntref3 c
ON s.scm_cntref3 = c.cr3_id";
q.qsp_what = 13 can be moved to a where
I happen to like this style
In the case of MSSQL T-SQL and some queries with a lot of joins I have gotten more efficient query plan by moving a where condition up into a join. The filter happened early rather that last.
If you don't believe you can put a hard value in a join see SQLfiddle
I have recently inherited a set of very large SQL Server databases. the application and database schema are a mess. I have run across a few fields in the database that store different types of sensitive data, where they should not be stored. since there are almost 10,000 tables in my database, I am in desperate need of a way to programmatically scan a few of these databases to find out where the data is. I realize this will be very resource intensive, so I have setup a server specifically to run a scan on backups of the databases.
I also have zero dollars for purchasing any tools.
Does anyone know of a way with C# and SQL that I can scan all user tables in the database for sensitive data?
an example of scanning for one type of data (eg. SSN) would be extremely helpful. I confident that I can extrapolate that into all the scenarios I would need.
this sql will list all user tables and row counts in a database. It will be a starting point..
SELECT o.name,
ddps.row_count
FROM sys.indexes AS i
INNER JOIN sys.objects AS o ON i.OBJECT_ID = o.OBJECT_ID
INNER JOIN sys.dm_db_partition_stats AS ddps ON i.OBJECT_ID = ddps.OBJECT_ID
AND i.index_id = ddps.index_id
WHERE i.index_id < 2 AND o.is_ms_shipped = 0 ORDER BY o.NAME
Hth,
O
This query will help you to find the column with particular name and datatype
SELECT t.name AS table_name,
SCHEMA_NAME(t.schema_id) AS schema_name,
c.name AS column_name ,tp.name
FROM sys.tables AS t
INNER JOIN sys.columns c ON t.OBJECT_ID = c.OBJECT_ID
INNER JOIN sys.types tp ON tp.user_type_id=c.user_type_id
WHERE c.name LIKE '%Product%' AND tp.name LIKE '%int%'
ORDER BY schema_name, table_name;
This might be irrelevant at this point of time but shall serve as an additional note: You can use Information Schema Views to query the database objects which comply with the ISO standard definition for the INFORMATION_SCHEMA.
MSDN LINK
If you can open the DB into Microsoft SQL Server Managment Studio, you can try to use ApexSQL . It's a plugin that can be downloaded from here:
http://www.apexsql.com/sql_tools_search.aspx
For example: you select the database and you can look for a column name. It will show you all tables in which you have that column.
Hope it helps.
I am having two different sql queries one written by me and one automatically generated by C# when used with linq, both are giving same results.
I am not sure which one to choose, Iam looking for
Whats the best way to choose one query out of many, when all returns same result (most optimized query).
Out of my queries (below written), which one should i choose.
Hand Written
select * from People P
inner join SubscriptionItemXes S
on
P.Id=S.Person_Id
inner join FoodTagXFoods T1
on T1.FoodTagX_Id = S.Tag2
inner join FoodTagXFoods T2
on T2.FoodTagX_Id = S.Tag1
inner join Foods F
on
F.Id= T1.Food_Id and F.Id= T2.Food_Id
where p.id='1'
Automatically Generated by LINQ
SELECT
[Distinct1].[Id] AS [Id],
[Distinct1].[Item] AS [Item]
FROM ( SELECT DISTINCT
[Extent2].[Id] AS [Id],
[Extent2].[Item] AS [Item]
FROM [dbo].[People] AS [Extent1]
CROSS JOIN [dbo].[Foods] AS [Extent2]
INNER JOIN [dbo].[FoodTagXFoods] AS [Extent3]
ON [Extent2].[Id] = [Extent3].[Food_Id]
INNER JOIN [dbo].[SubscriptionItemXes] AS [Extent4]
ON [Extent1].[Id] = [Extent4].[Person_Id]
WHERE (N'rusi' = [Extent1].[Name]) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[FoodTagXFoods] AS [Extent5]
WHERE ([Extent2].[Id] = [Extent5].[Food_Id])
AND ([Extent5].[FoodTagX_Id] = [Extent4].[Tag1])
)) AND ( EXISTS (SELECT
1 AS [C1]
FROM [dbo].[FoodTagXFoods] AS [Extent6]
WHERE ([Extent2].[Id] = [Extent6].[Food_Id])
AND ([Extent6].[FoodTagX_Id] = [Extent4].[Tag2])
))
) AS [Distinct1]
Execution Plan Results
Hand Written: Query Cost (relative to batch):33%
Linq Generated: Query Cost (relative to batch):67%
I have found that two different queries, one hand-written and one generated by Linq might look wildly different but, actually, when you analyse the query plan in SSMS, you find that actually they are almost identical.
You need to actually run these queries in SSMS with Display Actual Execution Plan switched on, and analyse the different plans. It's the only way to correctly analyse the two and find out which is better.
In general, Linq is actually very good at generating efficient queries; even if the actual SQL itself is pretty ugly (in some cases, it's the kind of SQL that a human would write if they had the time!). If course, that said, it can also generate some pigs!
Additionally, asking SO to help with performance of a query over so many tables is fraught with problems for us, since it will be governed so much by your indexes :)
But they aren't quite returning the same thing... The first query grabs everyting (SELECT *) while LINQ is going to extract what you really want (id and item). Trivial you may say but streaming back lots of data that's never used is a good waste of bandwidth and will make your application appear sluggish. Additionally, the LINQ query seems to be doing a lot more which may or may not be the correct solution especially as data is populated into FoodTagXFoods
As for which performs better, I couldn't tell you without something like the actual query plans and/or results of statistics io from both queries. My money is on hand-written but maybe because I like my hands.
Examining SQL Server Query Execution Plan is the best way to choose the better query.
Hope below tutorials help.
SQL Tuning Tutorial - Understanding a Database Execution Plan (1)
Examining Query Execution Plans
SQL Server Query Execution Plan Analysis
SQL SERVER – Actual Execution Plan vs. Estimated Execution Plan
I'm making a "reputation" type feature on my site similar to stack overflow.
I want to display their points on by their name in the header.
I don't want to have to do a db call just for this every time they move to another page.
Can anyone suggest a nice way to implement this?
Don't make a db call just for this but get the data from the database while you're getting everything else.
Follow the principle of One Request Response cycle, one database call. It's really just a matter of joining in the other tables in your query.
For instance, if you look at a page that has a question and a bunch of answers. You know the "user" of the original question and you know the "user" of each of the answers and comments. So while you're getting the information also join in the pertinent information of each of the users. It's really just joining in additional tables and you can effectively get all of the data you require in one database call.
When you make a call to a database (like MSSQL server) you can get back multiple resultsets in one call, so you're also not limited to a single result set.
Edit:
Here is a sample Stored procedure (or just SQL statements) that results in 5 result sets in one database call.
ALTER PROCEDURE [dbo].[GetPostWithSlug]
#PostSlug varchar(80)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #PostId int;
SELECT #PostId = PostId
FROM dbo.Post
WHERE PostSlug = #PostSlug
SELECT PostId, PostDate, PostSlug, dbo.[User].UserFirstName + ' ' + dbo.[User].UserLastName AS PostedBy, PostTitle, PostText, PostIsPublished, PostIsPublic, PostTitleImg, PostUpdatedDate, dbo.[User].UserWebsite AS AuthorWebsite
FROM dbo.Post
INNER JOIN
dbo.[User]
ON dbo.[User].UserId = dbo.Post.UserId
WHERE PostId = #PostId
/* SubCategories for Post */
SELECT dbo.PostSubCategory.PostId, dbo.Category.CategoryId, dbo.SubCategory.SubCategoryId, dbo.Category.CategoryDescription, dbo.SubCategory.SubCategoryDescription
FROM dbo.Category
INNER JOIN
dbo.SubCategory ON dbo.Category.CategoryId = dbo.SubCategory.CategoryId
INNER JOIN
dbo.PostSubCategory ON dbo.SubCategory.SubCategoryId = dbo.PostSubCategory.SubCategoryId
INNER JOIN
dbo.Post ON dbo.Post.PostId = dbo.PostSubCategory.PostId
WHERE dbo.Post.PostId = #PostId
ORDER BY dbo.PostSubCategory.PostId
/* Tags for Post */
SELECT dbo.PostTag.PostId, dbo.Tag.TagId, dbo.Tag.TagDescription
FROM dbo.PostTag
INNER JOIN
dbo.Tag ON dbo.Tag.TagId = dbo.PostTag.TagId
INNER JOIN
dbo.Post ON dbo.Post.PostId = dbo.PostTag.PostId
WHERE dbo.Post.PostId = #PostId
ORDER BY dbo.PostTag.PostId, dbo.Tag.TagDescription
/* Custom Groups for Post */
SELECT dbo.PostCustomGroup.PostId, dbo.CustomGroupHeader.CustomGroupHeaderId, dbo.CustomGroup.CustomGroupId
FROM dbo.CustomGroup
INNER JOIN
dbo.CustomGroupHeader ON dbo.CustomGroupHeader.CustomGroupHeaderId = dbo.CustomGroup.CustomGroupHeaderId
INNER JOIN
dbo.PostCustomGroup ON dbo.PostCustomGroup.CustomGroupId = dbo.CustomGroup.CustomGroupId
WHERE dbo.PostCustomGroup.PostId = #PostId
EXEC GetCommentsForPost #PostId
END
In C# code, your DbDataReader will hold multiple result sets and these can be got by calling NextResult(). Or if you're filling a DataSet you can simply use the Fill method of a adapter.
I use this technique on my blog Matlus - Internet Technology and Software Engineering and you can see how fast (responsive) the site is. The same technique is used on ExposureRoom which is a public social networking website that has a huge amount of traffic.
You're looking for some way to do donut hole caching:
https://stackoverflow.com/search?q=[asp.net-mvc]+donut+hole+caching
If it's only a small part of part of page that needs to be cached, you could use child action to render that part, and cache it. Example: http://www.asp.net/learn/whitepapers/mvc3-release-notes#_Toc276711791
Is it possible to do an inner join on 2 tables where both the tables are on different server??
Add a linked server (B) to server A then write the following query
SELECT
*
FROM
[SERVERB].[DATABASE].[SCHEMA].[TABLE] A
INNER JOIN [SERVERA].[DATABASE].[SCHEMA].[TABLE] B ON A.ID = B.ID
It is certainly possible in SQL code. How you would do it in C# I don't know but in SQl Server, I would set up linked servers and then the code is:
select t1.field1, t2.field2
From server1.database1.dbo.table1 t1
join server2.database2.dbo.table2 t2
on t1.id = t2.id
So you just use the four part name instead of the three part name. But you do have to have a linked server set up first.
You can download both tables to the client, then perform a join using LINQ.
For more detail, please provide more details.
If you are using SQL Server try using a Linked Server, if Oracle use a database link. I am not sure how it would be achieved in the rest.