@@ -0,0 +1,350 @@
< Query Kind = "Program" >
< Namespace > System . Threading . Tasks < / Namespace >
< / Query >
SqlConnectionStringBuilder csb = new SqlConnectionStringBuilder
{
IntegratedSecurity = true ,
MaxPoolSize = 500 ,
DataSource = "." ,
InitialCatalog = "Local.StackExchange.Meta"
} ;
const string LinqPadPath = @"C:\Linqpad\lprun.exe" ;
const bool runSequential = false ;
const int defaultThreads = 1 ;
const int defaultIterations = 2000 ;
const int toSkip = 0 ;
int ? toRun = 50 ;
List < Run > runs = new List < Run >
{
new Run ( @"select /* Models\Post.Answers.cs@51 */
p.* from Posts p where p.ParentId = @Id" , IdQueries . Questions ) ,
new Run ( @"
select c.Id
, c.PostId
, c.[Text]
, c.CreationDate
, convert(int, isnull(c.EditCount, 0)) [EditCount]
, c.Score
, c.ApplicationId
, c.UserId [OwnerId]
, coalesce(u.DisplayName, c.UserDisplayName, 'Anonymous') [OwnerName]
, convert(nvarchar(20), u.Id) [OwnerUrl]
, convert(bit, case when u.UserTypeId = 4 then 1 else 0 end) [OwnerIsMod]
, isnull(u.Reputation, 0) [OwnerReputation]
, convert(bit, 0) [UserHasVoted]
, convert(bit, 0) [UserHasFlagged]
from ( select row_number() over ( partition by cOrdered.PostId order by isnull(cOrdered.Score, 0) desc, cOrdered.CreationDate ) [Rank]
, cOrdered.*
from PostComments cOrdered
where cOrdered.PostId in (Select p.Id From Posts p Where p.ParentId = @postId Union Select @postId)
and cOrdered.DeletionDate is null
and isnull(cOrdered.Score, 0) >= 0) [c]
left outer join Users u on c.UserId = u.Id
where c.[Rank] <= 5
order by c.CreationDate
option ( optimize for ( @postId unknown ) )" , IdQueries . Questions , "postId" ) { Iterations = 2000 } ,
new Run ( @"select p.*, isnull(pm.ViewCount,0) ViewCount from Posts p /* Models\Post.Selecting.cs@122 */
left join PostMetadata pm on pm.PostId = p.Id
where p.Id = @id" , IdQueries . Questions ) ,
new Run ( @"Declare @Type tinyint = (2);
select p.Id /* Models\Post.RelatedQuestions.cs@114 */
, p.Title
, p.Score
, CAST(CASE
WHEN p.AcceptedAnswerId IS NULL THEN 0
ELSE 1
END AS BIT) AS HasAcceptedAnswer
, pl.Rank
, pl.CreationDate
from PostLinks pl
join Posts p on pl.RelatedPostId = p.Id
where pl.PostId = @Id
and pl.LinkTypeId = @Type
and p.DeletionDate is null" , IdQueries . Questions ) ,
new Run ( @"SELECT [t0].[Id], [t0].[UserTypeId], [t0].[Reputation], [t0].[LastAccessDate], [t0].[LastDailySiteAccessDate], [t0].[LastLoginDate], [t0].[LastEmailDate], [t0].[LastLoginIP], [t0].[CreationDate], [t0].[Email], [t0].[DisplayName], [t0].[WebsiteUrl], [t0].[RealName], [t0].[Location], [t0].[Birthday], [t0].[BadgeSummary], [t0].[OptInEmail], [t0].[PreferencesRaw], [t0].[HasReplies], [t0].[TimedPenaltyDate], [t0].[DaysVisitedConsecutive], [t0].[DaysVisitedTotal], [t0].[LastModifiedDate], [t0].[IsVeteran], [t0].[ReputationToday], [t0].[ReputationWeek], [t0].[ReputationMonth], [t0].[ReputationQuarter], [t0].[ReputationYear], [t0].[ReputationSinceLastCheck], [t0].[AcceptRateAsked], [t0].[AcceptRateAccepted], [t0].[AccountId], [t0].[ProfileImageUrl], [t0].[HasAboutMeExcerpt]
FROM [dbo].[Users] AS [t0]
WHERE [t0].[Id] = @p0" , IdQueries . Users , "p0" ) ,
new Run ( @"Select top 50
p.Id
, p.Title
, p.Score
, CAST(CASE WHEN p.AcceptedAnswerId IS NULL THEN 0 ELSE 1 END AS BIT) AS HasAcceptedAnswer
, pm.ViewCount
, p.AnswerCount
, p.AnswerScore
, x.LinkTypeId
, p.CreationDate
, p.LastActivityDate
From Posts p
Join PostMetadata pm On p.Id = pm.PostId
Join (select pl.RelatedPostId Id, pl.LinkTypeId
from PostLinks pl
where pl.PostId = @Id
and pl.LinkTypeId in (1, 3)
union
select pl.PostId, pl.LinkTypeId
from PostLinks pl
where pl.RelatedPostId = @Id
and pl.LinkTypeId in (1, 3)) x On p.Id = x.Id
Where p.DeletionDate is null
and p.PostTypeId = 1
Order By x.LinkTypeId Desc, ( ( log(isnull(ViewCount, 1) + 1) * 4 ) + ( ( ( isnull(AnswerCount, 1) * Score ) + 1 ) / 5 ) + ( isnull(AnswerScore, 0) ) ) Desc" , IdQueries . Questions ) ,
new Run ( @"SELECT [t0].[Id], [t0].[PostTypeId], [t0].[CreationDate], [t0].[Score], [t0].[Body], [t0].[OwnerUserId], [t0].[LastEditorUserId], [t0].[LastEditDate], [t0].[LastActivityDate], [t0].[LastActivityUserId], [t0].[ParentId], [t0].[AcceptedAnswerId], [t0].[Title], [t0].[Tags], [t0].[CommunityOwnedDate], [t0].[HistorySummary], [t0].[AnswerScore], [t0].[AnswerCount], [t0].[CommentCount], [t0].[FavoriteCount], [t0].[DeletionDate], [t0].[ClosedDate], [t0].[LockedDate], [t0].[OwnerDisplayName], [t0].[LastEditorDisplayName], [t0].[BountyAmount], [t0].[BountyCloses], [t0].[BountyClosed], [t0].[LastOwnerEmailDate], [t0].[ProtectedDate], [t0].[MigrationDate], [t0].[IsAcceptedAnswer], [t0].[IsAnswered], [t0].[HasNotices], [t0].[IsFrozen] AS [IsFrozenRaw], [t0].[QualityScore], [t0].[IsClosedAsDuplicate], [t0].[LastActivityTypeId]
FROM [dbo].[Posts] AS [t0]
WHERE [t0].[Id] = @p0" , IdQueries . AllPosts , "p0" ) ,
new Run ( @"SELECT /* Controllers\QuestionsController.Show.cs@318 */
MAX(CreationDate) FROM PostComments WHERE DeletionDate IS NULL AND PostId IN (SELECT Id FROM Posts WHERE Id = @Id OR ParentId = @Id)" , IdQueries . Questions ) ,
new Run ( @"SELECT /* Controllers\QuestionsController.Show.cs@330 */
LastRelatedQuestionRefreshDate from PostMetadata WHERE PostId = @Id" , IdQueries . Questions ) ,
new Run ( @"
SELECT /* Controllers\QuestionsController.Show.cs@324 */
MAX(DeletionDate) FROM Posts WHERE DeletionDate IS NOT NULL AND (Id = @Id OR ParentId = @Id)" , IdQueries . Questions ) ,
new Run ( @"
select u.Id, /* Controllers\QuestionsController.Show.cs@496 */
u.UserTypeId,
u.DisplayName,
u.Reputation,
u.BadgeSummary,
u.Email,
u.LastLoginIP,
u.TimedPenaltyDate,
u.ProfileImageUrl,
u.HasAboutMeExcerpt,
AcceptRateAsked,
AcceptRateAccepted
from Users u
where Id in (@Id)" , IdQueries . Users ) ,
new Run ( @"
Select PostTypeId,
Sum(Case When ClosedDate Is Not Null Then 1 Else 0 End) as ClosedPosts,
Sum(Case When ClosedDate Is Null And DeletionDate Is Null Then 1 Else 0 End) as OpenPosts,
Sum(Case When DeletionDate Is Not Null Then 1 Else 0 End) as DeletedPosts,
Sum(IsNull(CommentCount, 0)) Comments
From Posts
Where PostTypeId In (1,2)
Group By PostTypeId
Option(MAXDOP 4)" ) ,
} ;
void Main ( string [ ] args )
{
try
{
if ( args != null && args . Length == 1 )
{
int index ;
if ( int . TryParse ( args [ 0 ] , out index ) && index < runs . Count )
DoRun ( index ) ;
}
else
{
var runningCount = Math . Min ( toSkip + toRun . GetValueOrDefault ( runs . Count ) , runs . Count ) - toSkip ;
$ "{ runningCount } Quer{ ( runningCount == 1 ? "y" : "ies" ) } running...". Dump ( ) ;
var timers = new List < Stopwatch > ( runs . Count ) ;
for ( var i = toSkip ; i < toSkip + runningCount ; i ++ )
{
var j = i ;
var run = runs [ j ] ;
var procInfo = new ProcessStartInfo ( )
{
FileName = LinqPadPath ,
Arguments = $@ """{ Util . CurrentQueryPath } "" { j } ",
UseShellExecute = false ,
RedirectStandardOutput = true ,
RedirectStandardError = true ,
CreateNoWindow = true ,
WindowStyle = ProcessWindowStyle . Hidden
} ;
var pb = new Util . ProgressBar ( $ "Query { j } ")
{
HideWhenCompleted = true
} ;
var timer = Stopwatch . StartNew ( ) ;
timers . Add ( timer ) ;
var proc = Process . Start ( procInfo ) ;
proc . EnableRaisingEvents = true ;
proc . BeginOutputReadLine ( ) ;
proc . OutputDataReceived += ( s , e ) =>
{
if ( e . Data ? . Contains ( "workers started" ) == true ) timer . Restart ( ) ;
if ( e . Data ? . Contains ( "Done!" ) == true )
{
timer . Stop ( ) ;
pb . Visible = false ;
}
if ( e . Data ? . Contains ( " to run" ) == true )
{
var val = int . Parse ( e . Data . Replace ( " to run" , "" ) ) ;
run . Iterations = val ;
pb . Dump ( ) ;
}
if ( e . Data ? . Contains ( " runs complete" ) == true )
{
var val = int . Parse ( e . Data . Replace ( " runs complete" , "" ) ) ;
if ( run . Iterations > 0 )
{
pb . Fraction = ( val / ( double ) run . Iterations . GetValueOrDefault ( ) ) ;
pb . Caption = $ "Query { j } : { val } / { run . Iterations . GetValueOrDefault ( ) } ";
}
}
} ;
if ( runSequential ) proc . WaitForExit ( ) ;
}
while ( timers . Any ( t => t . IsRunning ) )
{
Util . Progress = ( timers . Count ( t => ! t . IsRunning ) / timers . Count ) ;
Thread . Sleep ( 1000 ) ;
}
var totalMs = timers . Sum ( t => t . ElapsedMilliseconds ) ;
var results = new List < Result > ( ) ;
$ "Total Run: { totalMs : n0} ms". Dump ( ) ;
for ( var i = 0 ; i < timers . Count ; i ++ )
{
results . Add ( new Result { Id = i , Duration = timers [ i ] . Elapsed , Run = runs [ i ] } ) ;
}
results . Select ( r => new { r . Id , r . Run . Iterations , r . Duration . TotalMilliseconds , r . Run . Query } ) . Dump ( ) ;
}
}
catch ( Exception e )
{
$ "{ e } ". Dump ( ) ;
}
}
public class Result
{
public int Id { get ; set ; }
public TimeSpan Duration { get ; set ; }
public Run Run { get ; set ; }
}
private SqlConnection GetConnection => new SqlConnection( csb . ConnectionString ) ;
List < List < int > > questionIds = new List < List < int > > ( ) ;
private void DoRun ( int id )
{
var run = runs [ id ] ;
ThreadPool . SetMinThreads ( run . Threads + 2 , run . Threads + 2 ) ;
$ "Id: { id } ". Dump ( ) ;
$ "Query: { run . Query } ". Dump ( ) ;
$ "Threads: { run . Threads } ". Dump ( ) ;
for ( var i = 0 ; i < run . Threads ; i ++ )
{
questionIds . Add ( new List < int > ( ) ) ;
}
if ( ! string . IsNullOrEmpty ( run . IdQuery ) )
{
using ( var conn = GetConnection )
using ( var cmd = conn . CreateCommand ( ) )
{
conn . Open ( ) ;
cmd . CommandText = run . IdQuery ;
cmd . Parameters . Add ( "runs" , SqlDbType . Int ) . Value = run . Iterations ;
using ( var dr = cmd . ExecuteReader ( ) )
{
int i = 0 ;
while ( dr . Read ( ) && i < run . Iterations )
{
questionIds [ i % run . Threads ] . Add ( dr . GetInt32 ( 0 ) ) ;
i ++ ;
}
$ "{ i } to run". Dump ( ) ;
}
}
$ "{ questionIds . Count } queues loaded". Dump ( ) ;
for ( var i = 0 ; i < questionIds . Count ; i ++ )
{
var j = i ;
$ "Queue { j } : { questionIds [ j ] . Count } items". Dump ( ) ;
}
}
else
{
$ "{ run . Iterations } to run". Dump ( ) ;
}
var workers = new Task [ run . Threads ] ;
for ( int i = 0 ; i < run . Threads ; i ++ )
{
var j = i ;
Task t = Task . Factory . StartNew ( ( ) => RunQueries ( run , questionIds [ j ] ) , TaskCreationOptions . LongRunning ) ;
workers [ j ] = t ;
}
$ "{ workers . Length } workers started". Dump ( ) ;
Task . WaitAll ( workers ) ;
$ "Done!". Dump ( ) ;
}
public static int procRuns ;
private void RunQueries ( Run run , List < int > queue )
{
var hasIds = ! string . IsNullOrEmpty ( run . IdQuery ) ;
using ( var conn = GetConnection )
{
conn . Open ( ) ;
using ( var ru = conn . CreateCommand ( ) )
{
ru . CommandText = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED" ;
ru . ExecuteNonQuery ( ) ;
}
using ( var cmd = conn . CreateCommand ( ) )
{
cmd . CommandText = run . Query ;
cmd . CommandTimeout = 600 ;
if ( ! string . IsNullOrEmpty ( run . IdQuery ) )
{
cmd . Parameters . Add ( run . IdParam , run . ParamType ) ;
foreach ( var Id in queue )
{
cmd . Parameters [ run . IdParam ] . Value = Id ;
cmd . ExecuteNonQuery ( ) ;
var result = Interlocked . Increment ( ref procRuns ) ;
$ "{ result } runs complete". Dump ( ) ;
}
}
else
{
foreach ( var Id in queue ) cmd . ExecuteNonQuery ( ) ;
}
}
}
}
public class Run
{
public string Query { get ; set ; }
public string IdQuery { get ; set ; }
public string IdParam { get ; set ; }
public SqlDbType ParamType { get ; set ; }
public int Threads { get ; set ; }
public int ? Iterations { get ; set ; }
public Run ( string query , string idQuery = null , string idParam = "Id" , SqlDbType paramType = SqlDbType . Int )
{
Query = query ;
IdParam = idParam ;
ParamType = paramType ;
IdQuery = idQuery ;
Threads = defaultThreads ;
Iterations = defaultIterations ;
}
}
public static class IdQueries
{
public const string Questions = "Select Top (@runs) Id From Posts Where PostTypeId = 1 Order By Id" ;
public const string Answers = "Select Top (@runs) Id From Posts Where PostTypeId = 2 Order By Id" ;
public const string Users = "Select Top (@runs) Id From Users Order By Id" ;
public const string AllPosts = "Select Top (@runs) Id From Posts Order By Id" ;
public const string Tags = "Select Top (@runs) Id From Tags Order By Id" ;
public const string ReviewTaskTypes = "Select Top (@runs) Cast(Id as int) Id From ReviewTaskTypes Order By Id" ;
public const string Accounts = "Select Top (@runs) AccountId From Users Where AccountId Is Not Null Order By Id" ;
public const string Badges = "Select Top (@runs) Id From Badges Order By Id" ;
}