How to answer questions politely and correctly

Back in August I wrote a long post about how to ask questions politely and correctly to address what I see as a growing volume of poorly asked questions by people who often don’t have the common courtesy to be polite and also often come across as feeling entitled to an answer. Based on the responses, and private discussions, many of you out there see the same trend and are dismayed by it.

This is the necessary corollary to that post – how to answer questions politely and correctly, in my opinion – because I see people being discourteous and sometimes unprofessional in their replies. I’ve woven in some of the replies and private distribution list discussions I’ve had over the last two months as well – thanks to those involved – you know who you are.

I’ll start out by saying that some of you will disagree with elements of what I state below. That’s cool, this is just my opinion – vive la différence, and all that – but don’t expect to convince me to change my views. We’ll agree to disagree :-)

Ignorance is Not Stupidity

Probably the number one sin I see people committing when answering questions is giving an attitude to the original poster (who I’ll call the OP from now on) that they’re stupid/lacking/deficient/lazy in some way for not knowing the answer themselves.

Now, if a simple Google search would have found the answer, then I can understand some frustration on the part of the answerer, and I suffer from it myself, but that’s no excuse to be rude or belittling. I even shy away from posting Let Me Google That For You links in such cases as I think that comes across as too snarky, and I like to stay polite as much as I can. But sometimes I’ll just post a Google search URL (especially on Twitter), which does the same thing, but without the added snark, as that would just make me look angry. Others disagree with this sentiment, I know, and will happily post LMGTFY links – each to his/her own.

If it’s not a simple Google search, or I can tell from the question that the OP wouldn’t know what to search on, or how to make sense of the search results, or know which one to choose, then I’ll answer politely and explain the answer. Even if it’s something really simple about SQL Server. (Also check out the insightful comments about Google searches in the comment from @sqlhandle.)

As I explained in my post Ignorance is not stupidity back in 2011, everyone in the world starts with zero knowledge about SQL Server. I knew zero about SQL Server when I joined Microsoft from DEC in February 1999 (15 years ago – OMG – I’m getting old!! :-). Especially if the OP is someone you don’t know, give them the benefit of the doubt and treat them with respect for having the guts to ask a question publicly to get help. Don’t slap someone down for not knowing the answer. That’s the height of conceit, it’s bullying, and it’ll likely drive the OP away from our wonderful online SQL Server community.

Ok – that’s one of my hot-button topics done.

Posting Links in Question Answers

Here’s another one: posting links in question answers.

There was an interesting debate on the MVP email list a week or so ago about this, where someone said they hesitate to post blog post links as an answer because it can come across as self-promotion. I vehemently argued against that point of view, and I continue to believe that posting blog post links in the answer (or even as the answer) is entirely justified.

Self-promotion is where you’re posting something solely to get clicks on a link, or to drive traffic to your website for some business purpose – which of course is bad and you shouldn’t do it in the answer to a technical question – unless it’s directly relevant in some way. Posting a link to a blog post that contains the answer that the OP needs, or helps explain the answer, is certainly not self promotion. It doesn’t matter that the link is to a blog post on your company website, that’s just where you blog, and if it makes them aware of your company, then I think that’s fair recompense for your time in answering a community question. it’s not blatant self-promotion.

I also don’t buy the argument that a bunch of the contents of said blog post should be reiterated in the answer, just to give some meat to the answer in the thread so the thread is ‘self-contained’, or because blog posts move. One of the reasons I blog about things is so I can reference them in classes and online, so I can avoid repeating myself and point people at a deeper reference as part of answer, or as the complete answer. This is especially important for question mediums like Twitter.

If in doubt, consult whatever guidelines exist for the forum/distribution list/medium on which you’re answering. And if I just drop in a blog post link, I’ll always say something like ‘If you have any follow-up questions, feel free to ask’.

Now, saying that, you need to be very confident that your blog post is actually correct and actually answers the question (or contributes to your answer).

Answering the Actual Question

Which brings me to my next point: make sure you’re answering the actual question.

Often I see someone post an answer to the question that shows that either a) they didn’t read the question to see what the OP was actually asking for, or b) they didn’t understand the question or what the OP was actually asking for.

This is quite prevalent on forums such as MSDN, where I’ll see people post just for the sake of posting to try to increase their forums points/score. This is just daft. What’s really interesting is that I don’t see this behavior at all on #sqlhelp, as the only merit gained from answering questions on Twitter is community respect, not some silly score. Other forums do it better by allowing up and down voting, which increases of decreases your score. I applaud people who answer lots of questions correctly, but if you’re only doing it to have a higher score than everyone else, then IMHO you need to go out and get a life.

Don’t post at all if you don’t know the answer and can’t help, otherwise you’re just noise that’s obscuring the answer for the OP and putting people off from following and helping out in that forum. This is what stopped me answering corruption questions on MSDN and other forums – having to continually (nicely) correct people who were answering incorrectly and then being berated for it.

If there isn’t enough information in the question to answer it correctly, ask for more information. Don’t just assume. Or maybe give a couple of different answers, for different conditions or SQL Server versions, state as much, and ask for clarification. If you assume some piece of information that can change the answer, you may be doing a huge disservice to the OP by giving them an answer that’s wrong for their situation.

Don’t just answer: It Depends.

Much of the time the answer really does start with It Depends, but you then need to explain why it depends, what it depends, how it depends, etc. It Depends is a valid start to an answer IMHO. See my post It Depends. It really, really does for more on this.

If you don’t have time to answer properly, don’t answer at all. A half answer, or a non-answer wastes everyone’s time. Step away and let someone else answer.

If the medium where the question is being asked isn’t appropriate to the question, direct the OP at an alternative medium. For instance, if someone posts a #sqlhelp question on Twitter asking for an explanation of whether to use one join type or another, or a comparison between mirroring and availability groups based on some facet of operation, they’ll be directed by someone to post the question on a forum so that longer answers can be given.

Summary

It all comes down to this: give a good answer, that answers the question, provides references if necessary, and leaves the OP feeling like they’ve had a good interaction with the SQL Server community.

Even if they don’t ask politely or correctly, don’t be a jerk when you answer. You can politely point out how to ask the question. The days of being able to hide anonymously on the Internet are well past – and your response is captured for all eternity, so take pride in answering politely and correctly.

Again, don’t be a jerk. Treat people with respect, and if they seem to be lacking in some way, educate them. But be nice about it.

Thanks

February 2015 Sydney IE2/IEPTO-2 class open for registration

We’ve managed to juggle some of our schedule around and found space to fit in our only class of 2015 in Australia, and it’s open for registration!

We’ll be bringing Jonathan and Erin with us to Sydney to teach our signature IEPTO-2 (formerly IE2) Immersion Event on Performance Tuning and Optimization.

The class will be February 23-27, and we’ve got a deep discount for prior students who’ve taken our IE1/IEPTO-1 class:

  • Regular price is US$3,995
  • Early-bird price is US$3,495 for registrations in 2014
  • Prior student special price is US$2,750

We’ll be giving registration priority to prior students as this is the only class we’ll be teaching in Australia in 2015, due to our schedule constraints.

You can get all the details on the class page here.

We hope to see you there!

Correctly adding data files to tempdb

It’s well known that one of the common performance issues that can affect tempdb is allocation bitmap contention. I discuss this, and ways to alleviate it, in these posts:

The current best advice around adding tempdb data files is enshrined in KB article 2154845. If you’re seeing tempdb allocation contention (see top blog post link above), then:

  • If your server has less than 8 logical cores (e.g. a one CPU server with 4 physical cores and hyperthreading enabled has 8 logical cores), use # tempdb data files = # logical cores, equally sized
  • If your server has more than 8 logical cores, start with 8 tempdb data files, and add sets of four at a time, equally sized, until the contention is alleviated

There are three problems that people often face when adding tempdb data files: matching the size of the existing files that are growing, adding a file doesn’t help with contention, and adding too many files.

Matching Existing File Sizes

This problem occurs when the existing tempdb data files are growing, and people find it hard to create additional files that match the size of the existing files.

There’s an easy method for doing this: don’t!

Don’t try to match the size of existing, growing files. Create the new files to be a bit larger than the existing files, then go back and increase the size of the existing files to match the size of the new files.

For example, if I have 4 tempdb data files sized at 6GB each, and they’re growing by 512MB every few minutes because of an ad hoc workload. If I decide to add 4 more files, I might decide to add the four new files at 10GB each, and then go back and do ALTER DATABASE [mydb] MODIFY FILE [DataFileX] (SIZE = 10GB) for each of the 4 existing files. Problem solved.

But also see the bottom section, where you may want to limit the total amount of space taken up by all your tempdb files if the only reason for extra files is to alleviate tempdb allocation contention.

Additionally, if you have one full data file, you may find that…

Adding a File Doesn’t Help

This is very frustrating when it happens to people because it gives the impression that adding tempdb data files does not help with allocation contention. However, there is a simple explanation for this phenomenon.

Consider the case where there is one tempdb data file. Obviously all the allocations have to come from that data file and with the right workload, allocation bitmap contention will result. After the server has been up for a while, and the workload has been running and using tempdb for a while, the single tempdb data file may become quite full.

Now let’s say that you decide to add one more tempdb data file. What happens to the allocations?

Allocation uses two algorithms: round-robin and proportional fill. It will try to allocate from each file in the filegroup in turn, but will allocate proportionally more frequently from files that have proportionally more free space than others in the filegroup.

In the case where one file is very full and the other file is very empty, the vast majority of the allocations will be from the new, empty file. This means that almost all the contention moves from the initially existing tempdb data file to the new one, without much alleviation of the overall contention.

If this happens to you, try adding some more data files so that the allocation system has multiple files that it will allocate from, spreading the contention over those files and leading to an overall drop in contention and increase in transaction throughput.

But beware of immediately…

Adding Too Many Data Files

This is the case where tempdb allocation contention is a problem and people immediately add a large number of additional files where fewer files would work just as well. The problem here is that additional disk space is used up for no real gain, which may or may not be significant in your environment, depending on the size of the files added.

Let’s do an experiment. Below is a screen shot of PerfMon measuring transactions per second in tempdb for a contrived workload that has 100 connections all repeatedly creating and truncating temp tables. It’s running on my laptop (8 logical cores) using SQL Server 2014 RTM CU3.

perfmon1 Correctly adding data files to tempdb

For the first third of the trace, there’s a single data file. For the middle third of the trace, there are two equally-sized files. For the final third of the trace, there are 8 equally-sized files.

Clearly there isn’t a big performance boost from having the additional 6 data files in the final third, but what’s the sweet spot?

Ideally you’d experiment with varying numbers of tempdb data files to find the sweet spot for your workload. However, that’s easier said than done, especially when you’re trying to standardize a tempdb configuration across multiple servers.

Here’s an example of a slightly different workload running under the same conditions on my laptop.

perfmon2 Correctly adding data files to tempdb

It starts with a single data file, then 2, 4, 6, and 8 (pausing perfmon between each file addition). In this case, it’s clearly worth it going to 8 data files. But would I make them all the same size as the initial data file?

No, not if the only reason I need the extra files is to alleviate the allocation bitmap contention. I’d lower the size of all the tempdb files, including the initial one, so I’m not taking up a huge amount of extra disk space for these files.

Just be aware that sometimes you don’t need to go all out and add a whole bunch of extra tempdb data files to get a performance boost.

Summary

The easiest way to alleviate tempdb allocation contention is to enable trace flag 1118 and to add more tempdb data files. Just be careful that you add the right number to help with the contention, you make all the files the same size, and that you take into account the total size of all the data files you’ve created, and possibly dial them all down a bit.

Enjoy!

2015 Chicago and Bellevue classes open for registration

I’ve just released our first sets of US classes for 2015 for registration!

Our classes in April/May will be in Chicago, IL:

  • IE0: Immersion Event for Junior/Accidental DBAs
    • April 27-29 (US$125 discount for registering in 2014)
  • IEPTO1: Immersion Event on Performance Tuning and Optimization – Part 1
    • April 27 – May 1 (US$200 discount for registering in 2014)
  • IEPTO2: Immersion Event on Performance Tuning and Optimization – Part 2
    • May 4-8 (US$200 discount for registering in 2014)
  • IEBI: Immersion Event on Business Intelligence
    • May 4-8 (US$200 discount for registering in 2014)
  • IEHADR: Immersion Event on High Availability and Disaster Recovery
    • May 11-15 (US$200 discount for registering in 2014)

Our classes in June will be in Bellevue, WA:

  • IEPTO1: Immersion Event on Performance Tuning and Optimization – Part 1
    • June 8-12 (US$200 discount for registering in 2014)
  • IEPTO2: Immersion Event on Performance Tuning and Optimization – Part 2
    • June 15-19 (US$200 discount for registering in 2014)

We’ll likely have some classes in the second half of 2015 (details in Spring 2015) but this is it for the first half as we’re going to Australia to teach in February.

As you can see, we’re offering discounts off the early-bird price for all our 2015 classes if you register before the end of this year. The regular early-bird prices will apply from January 1st, 2015. If you’ve previously attended an Immersion Event, there’s a larger discount that’s always available to you whenever you register.

You can get all the logistical, registration, and curriculum details by drilling down from our main schedule page.

We hope to see you there!

My upcoming precon workshop at PASS and SQLintersection

The two major Fall conferences are 3-4 weeks away so I wanted to give you a heads-up about my new pre-con workshop that I’ve just finished putting together and will be presenting at both the PASS Summit in Seattle at the start of November, and again the following week at our own SQLintersection conference in Las Vegas.

It’s based on one of my favorite topics – wait statistics and using them for performance troubleshooting - and that was the topic of my Spotlight session at the PASS Summit last year, which ended up being the #1-rated session. I’m very passionate about helping people learn about wait statistics and how to use them *correctly* as an invaluable aid when troubleshooting performance problems in SQL Server. Last year I only had 90 minutes on the subject (although I ran 40 minutes over!) but this year I’ll have an entire day to expand into techniques for further troubleshooting, rather than just evaluating the wait and latch statistics themselves.

The no-frills title of the workshop is: Performance Troubleshooting Using Waits and Latches

Here’s the abstract:

One of the first things you should check when investigating performance issues are wait and latch statistics, as these can often point you in the right direction for further analysis. Unfortunately many people misinterpret what SQL Server is telling them and jump to conclusions about how to solve the problem – what is often called ‘knee-jerk performance tuning’. In this full-day workshop, you’ll learn how to investigate and interpret wait and latch statistics – practical techniques you can take home and start using immediately. You’ll also learn what a myriad of wait and latch types actually mean and how you can investigate lightly-documented types to gain insight into what causes them. Don’t waste time when it comes to performance troubleshooting; wait statistics are the fastest route to understanding your problems and this workshop will help you get there faster.

If you come along I promise you that you’ll learn a ton of really, really useful information and techniques – I’m looking forward to teaching it tremendously.

You can get more details about this year’s PASS Summit in Seattle, November 3-7 at this website.

You can get more details about this year’s Fall SQLintersection in Las Vegas, November 8-14 at this website.

Whichever conference you go to (or you could be crazy like a few people I know and do both!), I’m looking forward to meeting you and I hope to see you in my workshop!

Cheers

Finding a table name from a page ID

This is a question that I was sent over email that I thought would make a good post, and I’m waiting to do a user group presentation in Australia at 2am, so this will keep me busy :-)

Imagine you come to work in the morning and notice that some new rows have been entered into the msdb.dbo.suspect_pages table during the night. Usually the first thing you’re going to do is run DBCC CHECKDB, but if your database is a few TB, that could be several hours before you know where the problem is, and which table may have lost data. You want to find out which table is involved as soon as possible so you can explore your disaster recovery options.

Another scenario is troubleshooting a poorly performing query workload, running my script to look at the currently waiting threads using sys.dm_os_waiting_tasks, seeing a lot of PAGELATCH_EX waits and needing to figure out which table is involved from the page ID in the resource_description column in the sys.dm_os_waiting_tasks output.

Going back to the first scenario, getting the data from the suspect_pages table is easy:

SELECT * FROM [msdb].[dbo].[suspect_pages];
GO
database_id file_id     page_id              event_type  error_count last_update_date
----------- ----------- -------------------- ----------- ----------- -----------------------
6           1           295                  2           2           2014-09-25 01:18:22.910

Finding the table name requires first using DBCC PAGE. The syntax for DBCC PAGE is:

dbcc page ( {'dbname' | dbid}, filenum, pagenum [, printopt={0|1|2|3} ])

You can just use print option 0, as that just displays the page’s header. You also must enable trace flag 3604 to get any output from DBCC PAGE – it’s perfectly safe. So taking the values from our suspect_pages output, that gives us:

DBCC TRACEON (3604);
DBCC PAGE (6, 1, 295, 0);
DBCC TRACEOFF (3604);
GO
PAGE: (1:295)

BUFFER:

BUF @0x00000004FD8C7980

bpage = 0x00000004A2D14000          bhash = 0x0000000000000000          bpageno = (1:295)
bdbid = 6                           breferences = 0                     bcputicks = 0
bsampleCount = 0                    bUse1 = 55116                       bstat = 0x809
blog = 0x15ab215a                   bnext = 0x0000000000000000          

PAGE HEADER:

Page @0x00000004A2D14000

m_pageId = (1:295)                  m_headerVersion = 17                m_type = 17
m_typeFlagBits = 0x0                m_level = 0                         m_flagBits = 0x8200
m_objId (AllocUnitId.idObj) = 84    m_indexId (AllocUnitId.idInd) = 256
Metadata: AllocUnitId = 72057594043432960
Metadata: PartitionId = 72057594039042048                                Metadata: IndexId = 0
Metadata: ObjectId = 245575913      m_prevPage = (0:0)                  m_nextPage = (0:0)
pminlen = 8008                      m_slotCnt = 1                       m_freeCnt = 83
m_freeData = 8107                   m_reservedCnt = 0                   m_lsn = (35:200:9)
m_xactReserved = 0                  m_xdesId = (0:0)                    m_ghostRecCnt = 0
m_tornBits = 1093512791             DB Frag ID = 1                      

Allocation Status

GAM (1:2) = ALLOCATED               SGAM (1:3) = ALLOCATED
PFS (1:1) = 0x64 MIXED_EXT ALLOCATED 100_PCT_FULL                        DIFF (1:6) = CHANGED
ML (1:7) = NOT MIN_LOGGED

We’re interested in the output beginning Metadata:. Those fields are not stored on the page itself. When I rewrote DBCC PAGE for SQL Server 2005, I added the Metadata: output to make it easier to find the object and index ID that the page is part of (as these used to be the m_objId and m_indexId fields in SQL Server 7.0 and 2000).

The Metadata: ObjectId field is what we want. If you see it is 99, then stop as that means the damaged page is part of the allocation system and not part of a table and you’ll need to wait for DBCC CHECKDB to complete to know the extent of the damage.

If you see the ObjectId is 0, that means there was no metadata found. This could be because:

  • The table that the page was part of has been deleted since the page corruption was logged
  • The system catalogs are corrupt in some way
  • The page is corrupt and so incorrect values were used to look up the metadata

In any case, you’ll need to wait for DBCC CHECKDB to complete to know the extent of the damage.

If the ObjectId is not 0 or 99, we can plug it into the OBJECT_NAME function to give us the name of the table:

SELECT OBJECT_NAME (245575913);
GO
--------------------------------------------------------------------------------------------------------------------------------
NULL

If you get the result above, then there are two possibilities:

  1. You are in the wrong database context
  2. The metadata for the database is corrupt, so wait for DBCC CHECKDB to complete

It’s most likely #1 that’s the problem, at least in my experience with helping people out. You can get the database name by taking the database_id in the suspect_pages output and plugging it into the DB_NAME function. Go into the correct database context and try again.

USE [company];
GO
SELECT OBJECT_NAME (245575913);
GO
--------------------------------------------------------------------------------------------------------------------------------
CustomerNames

So there you go – hope this helps!

PS1 Kenneth Fisher commented with some neat code that will do the job on 2012 and 2014 using the new sys.dm_db_database_page_allocations DMF – check it out. That will work as long as there aren’t any metadata or allocation bitmap corruptions.

PS2 Wayne Sheffield reminded me over email and in a comment that DBCC PAGE doesn’t need 3604 if you use the WITH TABLERESULTS option and programmatically crack the DBCC PAGE results.

Updated wait stats script for performance and 2014

Very short blog post to let you all know that I’ve updated my wait stats script so that it works on 2014 and also now runs very fast. If you’re using my script, please replace it with the new one.

Check it out on the original post: Wait statistics, or please tell me where it hurts.

Enjoy!

When is fast recovery used?

It’s been a bit light on technical posts here over the last few months but now that summer’s over I’ll be ramping up again with lots of cool stuff planned.

First up is a question that came up on the MCM distribution list this morning. There was a discussion of fast recovery (which I explained in detail in the post Lock Logging and Fast Recovery back in 2009), but in a nutshell is the ability of Enterprise Edition to allow access to a database after the REDO (rolling forward committed transactions) phase of crash recovery has completed and before the UNDO (rolling back uncommitted transactions) phase of crash recovery has completed. The idea is that UNDO can take much longer than REDO, so early access to the database is a good thing, hence it being an Enterprise Edition feature (from SQL Server 2005 onward).

The question essentially became: when is fast recovery used?

The answer is that it’s used whenever a database is started up and needs to have recovery run on it. This means fast recovery will be used:

  • When SQL Server starts up after a crash or shutdown where a database was not cleanly shut down
  • After a cluster failover
  • After a database mirroring failover
  • After an availability group failover
  • When a database state is changed to ONLINE and crash recovery needs to be run

Note that I did not include:

  • When restoring a database from backups
  • When bringing a log shipping secondary database online (this is restoring from backups)

Fast recovery is NOT used during a restore operation. You’ll read in some places online that it is, but those places are incorrect.

So why isn’t it used during a restore sequence?

It’s to do with the underlying mechanism that allows fast recovery. Operations that make changes to a database are logged, and the log record includes a bitmap of what locks were held at the time (examples of this are in the blog post I referenced above). When crash recovery runs, the REDO phase also acquires all the locks necessary to do the UNDO phase, as the REDO phase knows which transactions in the log being recovered need to be rolled back. At the end of the REDO phase, access can be given to the database because recovery can guarantee that no user can block the UNDO phase, as the UNDO phase locks are already held.

So why doesn’t that mechanism work for restores? Well restore doesn’t do one REDO and one UNDO like crash recovery does. For each backup that is restored in the restore sequence, the REDO phase of recovery is performed. This avoids having a really long REDO phase at the end of the restore sequence (which could be, say, a week’s worth of transactions spread over tens or hundreds of backups), and having to have a huge transaction log to hold all those log records.

At the end of the restore sequence, all necessary REDO has already been performed, but the REDO operations have NOT been acquiring UNDO locks. The UNDO locks aren’t acquired because UNDO isn’t likely to be the next phase during a restore sequence. It’s likely to be another restore operation. In that case, it’s likely that some of the transactions that were uncommitted at the end of the last restore become committed during the next restore, so if UNDO locks had been acquired, they would have to be released again. This would involve either rescanning the log records involved or keeping track of which in-restore transactions had acquired which locks. Either of these would be complicated and time consuming, so the benefit hasn’t been deemed worthwhile for the engineering effort involved.

So no fast recovery during restores.

But hold on, I hear you say, database mirroring is just a constant REDO process so how come fast recovery works for that? Back in SQL Server 2005, when a database mirroring failover occurred, the database was momentarily set offline so that full crash recovery would be run when the database came back online, hence allowing fast recovery to work. From SQL Server 2008 onward, that doesn’t happen any more, so there is a mechanism that figures out what UNDO locks are necessary when a mirroring failover occurs, allowing fast recovery behavior. I guess technically that same mechanism could be ported over to the restore code base, but I think it would be difficult to do, and I don’t think there’s enough demand to make the engineering effort and possible destabilization of the restore code worthwhile.

Hope this helps explain things – let me know if you have any questions.

New SQLskills Pluralsight courses

We’ve just released two new courses on Pluralsight:

The first new course is the conclusion of Joe Sack’s query-tuning course: SQL Server: Common Query Tuning Problems and Solutions – Part 2.

The second new course is Kimberly’s log-awaited SQL Server: Optimizing Stored Procedure Performance. It’s more than seven hours long and the abstract is:

When using stored procedures, their performance is dependent on creating the optimal plan for the execution environment and making sure that it remains cached. This comprehensive course will show you all of that and more, and is applicable to SQL Server developers and anyone responsible for ensuring performance of stored procedures, from SQL Server 2005 onward.

The module list is:

  • Introduction
  • Why Use Stored Procedures?
  • Creation, Compilation, and Invalidation Section 1
  • Creation, Compilation, and Invalidation Section 2
  • Optimization and Recompilation Section 1
  • Optimization and Recompilation Section 2
  • Optimization and Recompilation Section 3
  • Optimization and Recompilation Section 4
  • Other Concerns and Considerations

Check them out!

Also, some people have questioned the Basic/Intermediate/Advanced ratings and how they relate to our in-person classes. Any courses rated Intermediate on Pluralsight are the same level as our in-person content.

We’ve got a lot more courses in production and planned for the remainder of 2014 around DMVs, more stored procedure performance, Service Broker, Change Data Capture, fragmentation, and more. Watch this space (and the Insider Newsletter) for details.

Thanks!

How to ask questions politely and correctly

This post is a much-expanded version of the editorial in my last bi-weekly SQLskills Insider newsletter, including a bunch of the feedback I got.

(Also see my corollary post How to answer questions politely and correctly.)

Recently I’ve been complaining on Twitter about some of the ridiculous questions I receive over email (I get a bunch of SQL Server questions every day from random people across the world), where it was clear that the senders had done no research at all before sending me an email, or they demanded a response ASAP, or they didn’t say please or thank you, or a combination of all three. It gets pretty frustrating and it bugs me when people are demonstrably lazy and/or rude (usually without meaning to be). I see the same thing in forum questions too and occasionally on #sqlhelp on Twitter.

Don’t get me wrong, I like getting SQL Server questions in email, and I encourage class students to do it. I’m not being a grumpy old curmudgeon: I think people should learn how to ask questions properly. If you’re old enough to be responsible for SQL Server, you should have basic human-human communication skills.

I had feedback from the newsletter that some people might not know how to use Google/Bing. In this day and age, if someone is responsible for SQL Server in any way, shape, or form, and they don’t know how to search online, they shouldn’t be allowed near any I.T. infrastructure IMHO. I had a few people suggest sending Let Me Google That For You links as replies to emails where the answer can easily be found online, but I think that’s too snarky of a response and I don’t like to be rude.

I came up with a handy rule: if my 14-yr old smart daughter could find the answer on Google from your question, you’d shouldn’t post or ask in email.

But what about the concern of over-use of Google, so people never remember anything and rely on finding the answer online? And what if the answer is wrong? (Sometimes my life is this! :-) Yes, these are legitimate concerns. So maybe do the research and then ask a clarifying question or ask for corroboration from an authoritative source. And research the methodology for solving your problem, not just ‘the answer’. Teach yourself to fish rather than just finding the fish (mangling the old saying…)

And what about the concern about people wasting hours searching on Google rather than spending 5 minutes asking a question? That’s between you and your manager to work out how your company wants you to spend your time. But if you’re sending a random email question to someone *outside* your company, due diligence is not optional unless you’re paying for help.

This all brings to mind a training course from my days at Microsoft entitled Precision Questioning. The course taught how to hone your questioning technique for maximum efficacy, saving time for the questioner and the person/group being questioned. It also stressed the need to do due diligence in trying to find the answer to your question before taking up someone else’s time to help. I think something similar would be of great benefit to technical communities on the Internet where people ask questions.

Here are some quick guidelines for asking SQL Server questions I came up with (many of these apply to asking questions in general):

  • State your problem as unambiguously as possible.
  • State what research you’ve done before asking the question (this show’s you’ve done due diligence). You could even say what you searched for on Google/Bing.
  • State the SQL Server version/SP/CU/build you’re using.
  • State what you’ve done to try to alleviate your problem so far, if anything.
  • Ideally, include all Transact-SQL code to reproduce the phenomena (or, at least the details of the schema, indexes, query, query plan etc.) – just use your best judgment and include these as an annotated/commented script.
  • Include whatever results are pertinent.
  • Try to anticipate what people would ask to get more information, and provide answers in your question.
  • If you’re sending an unsolicited email to someone like me, consider this: if it’s going to take more than a minute or two to read the question, the answer’s going to be something like: this is too long to do in a quick email, please post on forum XYZ or let me know if you’d like some formal consulting help. Free questions are cool (to me), but don’t abuse the privilege. Note that this doesn’t apply if you know me or you’ve been invited to send questions (e.g. from being in a class). You might still get that same answer though, but it won’t be because you’ve abused the privilege.
  • Mandatory: say please and thank you.
  • Don’t demand urgent or immediate help. The only people who can ask for urgent assistance or use ASAP in their email are colleagues and people paying for help. Unless you’re in one of those categories, you’re not entitled to help – doesn’t matter how urgent your problem is. If your problem really is urgent, put yourself into one of those two categories. And even if you’re in one of those categories, make sure you frame the request so it isn’t too demanding as that can come across as rude.
  • DO NOT SEND THE SAME EMAIL QUESTION TO MULTIPLE PEOPLE INDIVIDUALLY. Seriously, this wastes people’s time by having multiple people respond to you. That’s what a forum is for. This is the #1 thing that annoys me and 100% guarantees a response stating that they will not get help from us (unless they’re paying, of course :-) Some people also expand this rule to include not posting the same question to multiple forums at the same time.

You might say to all of this that I have to consider the culture of the person asking the question and cut them some slack if they don’t say please or thank you, for instance. NO!!!! *They* need to consider *my* culture. That’s how communication works. The onus is on the person asking for help to make sure they’re communicating appropriately. This is *especially* true when sending random email. Along these lines, there’s a really great book that I recommend to anyone who interacts in a business setting with people outside their own culture: Kiss, Bow, or Shake Hands (and all its more focused companion titles).

If you’re using #sqlhelp on Twitter, most of this isn’t possible, and it’s accepted to not take up valuable tweet space with please and thank you. But asking a question over two tweets, using 1/2 and 2/2 is perfectly acceptable, and putting ‘Looked on Google already’ shows due diligence. You might be asked to post a longer question on a forum, in which case you should do so.

Whatever your chosen method for asking, make sure you respond to those who respond to you. Nothing puts people off from answering questions more than a complete lack of any thanks, or response to a clarifying question. And it’s just common courtesy (sadly lacking these days, especially in the relative anonymity of the internet).

I could sum all of this up by just asking people to be polite, conscientious, and grateful when asking questions.

If you’re reading this and thinking ‘OMG I sent a question to Paul and didn’t do those things, now he hates me’, you can stop panicking. If you really weren’t polite, demanded urgent help, or showed lack of any research, I would have let you know in my reply.

And don’t forget, this isn’t just for asking questions online, these guidelines should help within your company as well. Feel free to use this list, forward this post, or use it in a way that will help you or your company. I don’t mean this to be a marketing post, but a lot of what I have here is covered in my Communications: How to Talk, Write, Present, and Get Ahead! course on Pluralsight.

Now, where can you ask your question online?

And a whole bunch of other places where people give out help for free, but these are the main ones as far as I’m concerned.

To finish off, I leave you with two blog posts I wrote three years ago:

The more information you can provide, show you’ve tried on your own to find an answer, and are polite and grateful, the more likely you’ll get useful answers quickly. And if you’re sending direct email, you’d better do all of this if you want a reply. Often you’ll find that going through the rigmarole of putting all this into your question will help you get to the answer on your own, so problem solved!

You’ll be amazed at the great help you can get online for free… if you ask properly!

PS Happy to hear your thoughts on this. If I’ve missed anything I’ll update the post based on your comment.