16 August 2016

How You Can Crack Another Session's Temp Table, And Why You Might Want To

One of the understood behaviors of a SQL Server temporary table is that (aside from global temp tables) you can't peek into them from another session. Your temp table is your own and nobody else can access it (although sysadmins can at least find row counts in tempdb, which can be handy). But every now and then you run into an odd situation where it would be incredibly handy to find out what's inside of a temporary table that you didn't create.

For instance, say you have a batch process that has been running for hours, and seems to be doing nothing of interest. You look into the code that is running, and it has a while loop based on a count of the rows in a temp table. The exact methods can and do vary considerably, this is a completely contrived example.

SET NOCOUNT ON;CREATE TABLE #TempTable ( Col1 INT, Col2 CHAR(2000));INSERT INTO #TempTable VALUES (-42691,'Odd Record'),(0,'A'),(1,'A'),(2,'A'),(3,'A'),(4,'A'),(5,'A'),(6,'A'),(7,'A'),(8,'A'),(9,'A'),(10,'A');
DECLARE @i INT = 0;WHILE EXISTS (SELECT * FROM #TempTable)BEGIN
   WAITFOR
DELAY '00:00:01';

  
--Do something with the record

  
DELETE FROM #TempTable WHERE Col1 = @i;
  
SET @i = @i+1;END


Now you may look at that and see the obvious logical flaw here, but if the table population wasn't visible to you, it might not be so clear. So you see that it is spinning forever in this while loop, and you can tell from various DMVs that the table exists with one row. But you can't see inside the table to find out why. OR CAN YOU? First let's grab the object ID...note the percent wildcard, important because SQL Server appends a bunch of silly stuff on the name:

SELECT name, [object_id], type_desc, create_date FROM tempdb.sys.tables WHERE name LIKE '#TempTable%'

name object_id type_desc create_date
#TempTable____________________000000011F66 -1590458413 USER_TABLE 2016-08-16 11:55:02


Make sure the create_date matches up to what you would expect (in case you grab a wrong but similarly named table) and take the object_id value and plug it into either DBCC IND, or my current favorite, sys.dm_db_database_page_allocations:

SELECT index_id, allocation_unit_type_desc, allocated_page_page_id, page_type, page_type_desc, page_level, extent_file_id FROM sys.dm_db_database_page_allocations (DB_ID(), -1590458413, NULL, NULL, 'DETAILED') WHERE is_allocated = 1 ORDER BY index_id, page_type;

index_id allocation_unit_type_desc allocated_page_page_id page_type page_type_desc page_level extent_file_id
0 IN_ROW_DATA 681 1 DATA_PAGE 0 1
0 IN_ROW_DATA 939 10 IAM_PAGE 0 1


In this example, we can ignore the IAM page and go straight to the one (currently) allocated data page. Note both the file ID and page ID...often very important for tempdb where multiple files is more the norm.

DBCC TRACEON (3604);DBCC PAGE (tempdb, 1, 681, 3) WITH TABLERESULTS;

If you're new to DBCC PAGE, just Google Paul Randal and DBCC PAGE and you'll be off in no time. Just don't confuse it with DBCC WRITEPAGE or it will be a bad, bad day for you. But once you scan on down through, you can see your record. Col1 with a negative value, and our oddly written increment logic (starting from zero) will never hit that. So that's where our endless loop came from!

ParentObject Object Field VALUE
PAGE HEADER: Slot 0 Offset 0x60 Length 2011 Record Type PRIMARY_RECORD
PAGE HEADER: Slot 0 Offset 0x60 Length 2011 Record Attributes  NULL_BITMAP
PAGE HEADER: Slot 0 Offset 0x60 Length 2011 Record Size 2011
Slot 0 Offset 0x60 Length 2011 Memory Dump @0x000000003078A060 0000000000000000:   1000d807 3d59ffff 4f646420 5265636f 72642020  ..Ø.=YÿÿOdd Record  
Slot 0 Offset 0x60 Length 2011 Memory Dump @0x000000003078A060 0000000000000014:   20202020 20202020 20202020 20202020 20202020                      
extra rows…
Slot 0 Offset 0x60 Length 2011 Memory Dump @0x000000003078A060 00000000000007D0:   20202020 20202020 020000                             
Slot 0 Offset 0x60 Length 2011 Slot 0 Column 1 Offset 0x4 Length 4 Length (physical) 4 Col1 -42691
Slot 0 Offset 0x60 Length 2011 Slot 0 Column 2 Offset 0x8 Length 2000 Length (physical) 2000 Col2 Odd Record         

As seemingly obscure as this may appear, I have had to use it to find root cause of a production issue. Kudos to the Pauls (both White and Randal)...the former's article helped me last year when I needed to try this out the first time, and the latter's various blog posts and SQLskills training has helped me a lot in sorting out how and when to use these useful undocumented commands like DBCC PAGE.

Happy data hacking!

15 August 2016

Estimating Completion Times of a SQL Process

This is the sort of query I've written from scratch a hundred times, or done manually using my trusty old friend calc.exe. You have a running process, and you know it has to chew through so many rows, and you have a count (possibly with a nolock hint) query that can see how many it has processed, or many are remaining to process. Well, I finally wrote out an adaptable version of this query that I can use as a template when I'm trying to quickly gauge how long a process is going to take. Basically you adjust the two "count" queries for your specific scenario, set either a target count query or a target fixed value (can be zero if you're counting backwards), and set a delay time between the two count values.

DECLARE
        
@t INT,                 --Target value
        
@c1 INT,                --First count value
        
@c2 INT,                --Second count value
        
@tm1 DATETIME,          --First time value
        
@tm2 DATETIME;          --Second time value

--Alter delay value depending how patient you are.

DECLARE @SampleDelay CHAR(8) = '00:01:00';

--Determine Target Count
--Alter the following based on the specifics of the situation, or use a hard coded value:

SELECT @t=
--COUNT(*) FROM someTable WHERE WITH (NOLOCK) ThisValue='this';

--Determine First Count

SELECT @tm1=GETDATE(), @c1=
--Alter the following based on the specifics of the situation:
--COUNT(*) FROM someOtherTable WITH (NOLOCK) WHERE ThisValue='that';

--Variable Delay

WAITFOR DELAY @SampleDelay;

--Determine Second Count
SELECT @tm2=GETDATE(), @c2=
--Alter the following based on the specifics of the situation...should be same as first count query barring variable names
--COUNT(*) FROM someOtherTable WITH (NOLOCK) WHERE ThisValue='that';

--Compute Estimates

PRINT 'Target Count:         ' + CAST(@t AS VARCHAR(100));
PRINT 'Initial Count:        ' + CAST(@c1 AS VARCHAR(100)) + ' at ' + CAST(@tm1 AS VARCHAR(100));
PRINT 'Second Count:         ' + CAST(@c2 AS VARCHAR(100)) + ' at ' + CAST(@tm2 AS VARCHAR(100));
PRINT 'Elapsed seconds:      ' + CAST(DATEDIFF(second,@tm1,@tm2) AS VARCHAR(100));
PRINT 'Records processed:    ' + CAST(ABS(@c2-@c1) AS VARCHAR(100));
PRINT 'Rate per second:      ' + CAST(((@c2-@c1)*1.0)/DATEDIFF(second,@tm1,@tm2) AS VARCHAR(100));
PRINT 'Records remaining:    ' + CAST(ABS(@t - @c2) AS VARCHAR(100));
PRINT 'Seconds remaining:    ' + CAST(CAST((@t - @c2)/(((@c2-@c1)*1.0)/DATEDIFF(second,@tm1,@tm2)) AS INT) AS VARCHAR(100));
PRINT 'Estimated completion: ' + CAST(DATEADD(second,(@t - @c2)/(((@c2-@c1)*1.0)/DATEDIFF(second,@tm1,@tm2)), GETDATE()) AS VARCHAR(100));


Gives you rate information, time and records remaining, and calculates an estimated completion time. Here's a sample of the output:

Target Count: 20000
Initial Count: 1346 at Aug 15 2016 2:05PM
Second Count: 1498 at Aug 15 2016 2:06PM
Elapsed seconds: 60
Records processed: 152
Rate per second: 2.533333333333
Records remaining: 18502
Seconds remaining: 7303
Estimated completion: Aug 15 2016 4:08PM




21 July 2016

Estimating Size When Dropping a Clustered Columnstore Index

SQL Server 2014 introduced clustered columnstore indexes which have proven to be very handy in our shop for large data warehouse "fact" tables. The compression algorithm they use is very efficient and (dependent on data of course) can compress data down at ratios that make conventional B-tree row and page compression look pretty anemic in comparison. But, there's an ironic downside to this great compression performance...

Clustered columnstore indexes aren't great for running mass updates. They are best for relatively static data. So our BI team tends to drop the columnstore index and build conventional indexes (clustered or non-clustered) to support an update on one of these tables, then rebuild the columnstore after the update. It's a slow, painful process, but it works. However, every now and again somebody forgets just how great columnstore compression is and drops the columnstore index, effectively building a massive uncompressed B-tree heap. This operation can easily fill a drive if it is a large enough table and drive space has not been attended to. So estimating the size of the table uncompressed becomes essential.

Microsoft walks you through the process for Heaps, Clustered Indexes, and Non-Clustered Indexes. The non-leaf level index estimation requires a bit more complexity, so you're generally best doing it by hand, but for basic leaf-level/heap estimation, I decided to automate the process so you can just plug in your table name, and estimate the size of the uncompressed heap by examining the columns. It isn't ideal for a variety of things...obscure data types, sparse columns, and if you have a lot of variable data types you're better off computing the AVG(LEN(column)) manually to get a more accurate length of that column, on average. But for our tables, mostly with static length columns, it is pretty handy.

----ALTER THESE VALUES, RUN IN CORRECT DB----DECLARE @SchName SYSNAME = 'dbo';DECLARE @TblName SYSNAME = 'FACT_CLAIM_HISTORY';---------------------------------------------
DECLARE @IxName SYSNAME, @ExistingPages INT, @ExistingMB INT;
SELECT @IxName = name FROM sys.indexesWHERE OBJECT_SCHEMA_NAME(object_id)=@SchName AND OBJECT_NAME(object_id)=@TblNameAND index_id=1 and [type]=5;
SELECT @ExistingPages = SUM(a.total_pages) FROM sys.partitions pINNER JOIN sys.allocation_units a ON p.[partition_id] = a.[container_id]WHERE OBJECT_SCHEMA_NAME(object_id)=@SchName AND OBJECT_NAME(object_id)=@TblName;
SELECT @ExistingMB = (8 * @ExistingPages) / 1024;
IF (@IxName IS NULL)BEGIN
PRINT
'No clustered columnstore index on that table.';END
ELSE
BEGIN
   DECLARE
      
@TotalRows INT,
      
@TotalColumns INT,
      
@StatCols INT,
      
@DynCols INT,
      
@StatColBytes INT,
      
@DynColBytes INT,
      
@DynColBytesTracking INT,
      
@NullBitmapBytes INT,
      
@RowBytes INT,
      
@RowsPerPage INT,
      
@TotalPages INT,
      
@TotalSizeMB INT;

  
PRINT 'Table Name: ' + @SchName+'.'+@TblName;
  
PRINT 'Index Name: ' + @IxName;

  
--Total Rows
  
SELECT @TotalRows = SUM([rows]) FROM sys.partitions
  
WHERE OBJECT_SCHEMA_NAME(object_id)=@SchName AND OBJECT_NAME(object_id)=@TblName;
  
PRINT 'Total Rows: ' + CAST(@TotalRows AS VARCHAR(100));

  
--Total Columns
  
SELECT @TotalColumns = COUNT(*) FROM sys.columns
  
WHERE OBJECT_SCHEMA_NAME(object_id)=@SchName AND OBJECT_NAME(object_id)=@TblName;
  
PRINT 'Total Columns: ' + CAST(@TotalColumns AS VARCHAR(100));

  
--Total Static Length Columns
  
SELECT @StatCols = COUNT(*) FROM sys.columns c
  
INNER JOIN sys.types t ON t.system_type_id = c.system_type_id
  
WHERE OBJECT_SCHEMA_NAME(c.object_id)=@SchName AND OBJECT_NAME(c.object_id)=@TblName
  
AND t.name NOT LIKE 'var%' AND t.name NOT LIKE '%text';
  
PRINT 'Total Static Length Columns: ' + CAST(@StatCols AS VARCHAR(100));

  
--Total Variable Length Columns
  
SELECT @DynCols = COUNT(*) FROM sys.columns c
  
INNER JOIN sys.types t ON t.system_type_id = c.system_type_id
  
WHERE OBJECT_SCHEMA_NAME(c.object_id)=@SchName AND OBJECT_NAME(c.object_id)=@TblName
  
AND ( t.name LIKE 'var%' OR t.name LIKE '%text');
  
PRINT 'Total Variable Length Columns: ' + CAST(@DynCols AS VARCHAR(100));

  
--Total Static Length Column Bytes
  
SELECT @StatColBytes = ISNULL(SUM(c.max_length),0) FROM sys.columns c
  
INNER JOIN sys.types t ON t.system_type_id = c.system_type_id
  
WHERE OBJECT_SCHEMA_NAME(c.object_id)=@SchName AND OBJECT_NAME(c.object_id)=@TblName
  
AND t.name NOT LIKE 'var%' AND t.name NOT LIKE '%text';
  
PRINT 'Total Static Length Column Bytes: ' + CAST(@StatColBytes AS VARCHAR(100));

  
--Max Variable Length Column Bytes
  
SELECT @DynColBytes = ISNULL(SUM(c.max_length),0) FROM sys.columns c
  
INNER JOIN sys.types t ON t.system_type_id = c.system_type_id
  
WHERE OBJECT_SCHEMA_NAME(c.object_id)=@SchName AND OBJECT_NAME(c.object_id)=@TblName
  
AND ( t.name LIKE 'var%' OR t.name LIKE '%text');
  
PRINT 'Maximum Variable Length Column Bytes: ' + CAST(@DynColBytes AS VARCHAR(100));

  
--Total Variable Column Bytes with Tracking Bytes
  
SELECT @DynColBytesTracking = CASE WHEN (@DynCols > 0) THEN (2 + (@DynCols * 2) + @DynColBytes) ELSE 0 END;
  
PRINT 'Total Variable Length Column Bytes With Tracking: ' + CAST(@DynColBytesTracking AS VARCHAR(100));

  
--Null Bitmap Bytes
  
SELECT @NullBitmapBytes = 2 + ((@TotalColumns + 7) / 8);
  
PRINT 'Null Bitmap Bytes: ' + CAST(@NullBitmapBytes AS VARCHAR(100));

  
--Row Size Bytes (including header bytes)
  
SELECT @RowBytes = @StatColBytes + @DynColBytesTracking + @NullBitmapBytes + 4;
  
PRINT 'Row Bytes: ' + CAST(@RowBytes AS VARCHAR(100));

  
--Rows Per Page
  
SELECT @RowsPerPage = 8096 / (@RowBytes + 2);
  
PRINT 'Rows Per Page: ' + CAST(@RowsPerPage AS VARCHAR(100));

  
--Total Pages
  
SELECT @TotalPages = ROUND((@TotalRows * 1.0) / @RowsPerPage, 0);
  
PRINT 'Total Pages: ' + CAST(@TotalPages AS VARCHAR(100));

  
--Heaap size in megabytes
  
SELECT @TotalSizeMB = (8 * @TotalPages) / 1024;
  
PRINT 'Total Size, MB: ' + CAST(@TotalSizeMB AS VARCHAR(100));

  
--Current (compressed) values
  
PRINT 'Current (compressed) Pages: ' + CAST(@ExistingPages AS VARCHAR(100));
  
PRINT 'Current (compressed) Size, MB: ' + CAST(@ExistingMB AS VARCHAR(100));

  
--Compression Ratio, for fun...
  
PRINT 'Compression Ratio: ' + CAST((@TotalSizeMB*1.0/@ExistingMB) AS VARCHAR(100));

END


Here's some sample output:
Table Name: dbo.FACT_CLAIM_HISTORY
Index Name: CCIX_FACT_CLAIM_HISTORY
Total Rows: 282749658
Total Columns: 79
Total Static Length Columns: 79
Total Variable Length Columns: 0
Total Static Length Column Bytes: 405
Maximum Variable Length Column Bytes: 0
Total Variable Length Column Bytes With Tracking: 0
Null Bitmap Bytes: 12
Row Bytes: 421
Rows Per Page: 19
Total Pages: 14881561
Total Size, MB: 116262
Current (compressed) Pages: 3211431
Current (compressed) Size, MB: 25089
Compression Ratio: 4.633983020447





01 July 2016

Giving Venison Its Due Respect

By way of introduction, I should clarify that I'm not a good hunter. I'm laughably bad at it. I wasn't taught to hunt at an early age; my first experience hunting was in my thirties. Even now after a couple years I'm still borderline helpless with things like wind direction and other high arts that are seemingly innate to the lifelong, skilled deer hunter. But my daughter, then five, tasted venison backstrap at a neighbor's house and subsequently issued a dictum to me that I must get her a deer, and I accepted the challenge, somewhat compensating for my lack of skill, knowledge, and experience with sheer force of bloody-minded will and patience. I learned to shoot a compound bow and crossbow in order to maximize potential opportunities for hunting seasons, and I gradually outfitted myself with all the required gear (and some, I discovered, not so required). My first season in 2014 I spent 100 hours in total from September to December, with no luck, but a lot of observation.

Last year, more of the same.


However, the first day of rifle season, a trio of does sauntered within range of my Enfield and at long last, success.


Thanks to a lot of self-teaching, I field-dressed the deer on my own, then hung it and processed it myself. In deference to the squeamish, the less said about that, the better. Finally, what I'd been after...a freezer full of venison.


Here's where things take a turn and where I differ in approach from a number of excellent hunters. I'll never be a great hunter, I know that. I can work to improve my odds as I learn from experience, but I'll never be that guy tracking a grizzly bear for days through the Alaskan wilderness or calling in bugling elk bulls with ease. However, what might be within my reach is to be a good cook. The tragedy of venison to me is that it is one of the finest meats available...the meat once reserved for kings...and in America, it tends to be ground up into burger, stewed into chili, or a variety of other serviceable and reasonable (but slightly mundane) culinary fates. (Perhaps that is not quite true, the more tragic thing for me is the unending parade of dead, festering deer left to rot on the side of busy highways...a much more wasteful and less humane end for a deer.) For some reason, every other hunter venison recipe I come across uses either bottled Italian dressing as a marinade, or canned cream of mushroom soup. I'm not sure how cream of mushroom soup and Italian dressing became the ubiquitous components of a the hunter's pantry...kind of an odd couple of anomalies in the space time continuum. Why those things specifically?

Anyhow, my intent was, in order to pay the most respect to this animal, to ensure that every meal I make with it would be a bit special, a sort of round-the-world tour for the deer. So without further ado:

Greek Roasted Leg of Venison

An entire front leg and shoulder were carefully marinated in a Greek marinade with lots of garlic, olive oil, and oregano, and then smoke-roasted whole on the grill. Served with a salad, hummus, olives, pita, rice, feta, and a nice white wine. In the future I might try this with a different cut...the many muscles of the whole leg were relatively tough and hard to get cooked evenly without overcooking, but the taste was excellent, similar to lamb.

Venison Pie

A variant of the English classic Shepherd's Pie, using (as is common for the original dish) shredded leftovers from the roast. Well-browned onion with minced carrot and tart apple go into the filling with the meat and a makeshift brown gravy, seasoned with Worcestershire and a bit of catsup, and stewed til tender, then topped with potato mash and Cheddar, and baked.

Venison Barbacoa

Having learned a lesson from the slightly tough Greek roast, the other front leg was broken down into sections, and then slowly simmered all day in a Mexican style broth with chilies, onion, cumin, cinnamon, oregano, and garlic. Once completely tender, it is deboned, shredded, and added back into the broth. Served with tortillas, rice, black beans, sour cream, pico de gallo, olives, lettuce, and homemade queso fresco.

Venison Liver Pâté

I went into this with some trepidation, not being a fan of liver, but having saved the large, intact liver from the doe, not wishing it to go to waste. After kicking around the idea of braunschweiger, I opted instead to go for a French pâté, albeit with venison liver. After soaking the liver in buttermilk overnight, I sautéed it with bacon and a good amount of shallots. Then after processing it with butter, cream, spices, and port wine, I packed in small (but not small enough...a little of this goes a long way) jars and baked it a bit further in a water bath. Served with a baguette my wife made, and the accompanying port is essential (by all means, take the upgrade to Armagnac if you wish). Takes fortitude to work your way through something as "richly flavored" as this, I admit.

Norwegian Grilled Backstrap with Gjetost Sauce

Finally I broke out the backstrap...the long, lean loin muscle on either side of the spine on the animal. This is one of my favorite recipes that I borrowed from Andreas Viestad...his original uses venison, but in years past I would use beef sirloin as a substitute due to my lack of venison, and I've always grilled instead of panfried in my version. Fennel and juniper are used to provide a rub, and after grilling to medium-rare (these ones look almost more rare, but venison is quite red to begin with, compared to beef), I made a sauce with some stock, sour cream, more juniper and fennel, and a fantastic albeit rare ingredient, Norwegian gjetost cheese. It is a caramelized brown goat cheese that adds a lovely almost sweet (but still savoury) flavor to the sauce. Spätzle isn't exactly authentic, but it pairs nicely enough.

Kung Pao Venison

Slicing some thin sections of meat off of a leg roast, I made a wok-full of this Szechuan specialty. Velveted the meat, and stirfried with vegetables and peanuts. As is my usual practice I ended up making it a bit spicy for the kids, unfortunately, and Debra was not a great fan of the mouth-numbing effects of the Szechuan peppercorns. Other than that, not bad at all.

Poronkäristys

Back over to Scandinavia for this Finnish specialty, translated as "Sautéed Reindeer". We're a bit too far south for reindeer or caribou, but whitetail is close enough for me. Strips of meat are shaved off a semi-frozen roast as thinly as possible, then it is sautéed with onion, salt, and pepper, and a bit of beer. In this case, homebrewed sahti, a very old unboiled, unhopped style ale from Finland that is brewed with branches of juniper. The meat is served on mashed potatoes and accompanied by fried mushrooms, lingonberry, and more sahti.

Venison Jägerschnitzel

A proper German "hunter's cutlet", thin breaded cutlets fried in butter, with a mushroom cream sauce. The acorn spätzle was no one's favorite except Peter who ate it with gusto...made with flour processed from white oak acorns, had a bit too much bitterness for our liking, but certainly edible. Doppelbock (not home-brewed...I tend to stick to top-fermented beers these days) to accompany.

Tacos de Venado al Pastor

Returning, as Jimi might say, "way down, to Mexico way", I marinated and grilled flank steak to make a rough equivalent to tacos al pastor, with grilled pineapple, salsa, guacamole, lime, smoked cheese, and marinated onions. Hadn't sliced it up yet in this pic, just fresh off the grill.

Venison Anticuchos

Thence further south to Peru for anticuchos. Anticuchos are marinated and grilled beef heart kebabs, essentially, and having achieved a double lung shot, the heart was in fine condition, so I kept it...carefully trimmed and cut up, it is more like steak than one's usual idea of organ meats. The marinade is a spicy concoction of smoked chilies, wine vinegar, and herbs...a bit spicier than my kids liked, but great flavor. Accompanied with grilled corn and potatoes, aji verde, and pisco sours.

Venison Pastrami

Lurching northwards up to the Jewish delicatessens of New York City, I took a leg roast and brine cured it for a few days, then cold smoked it for a few hours at refrigerator temperatures. Then a pepper-coriander rub, followed by hot-smoking until cooked. Thinly sliced on a meat slicer, and served with mustard and pickles on marble rye. The wine is, of course, completely ridiculous, but it completes the tableau, one might say...I couldn't find the celery soda (Cel-Ray is it?) served in many delis.

Venison Gulyás

The tough, collagen-rich shank is ideal for a pot of Hungarian gulyás, or goulash. Traditionally cooked outdoors over a fire in a bogrács (kettle), a great way to enjoy the early spring weather. Onions, peppers, carrots, various spices (but large quantities of paprika) go into this, and the meat is slowly braised into tenderness. Then near the end, in go the csipetke, small pinched pasta or dumplings.

Served with a cherry pálinka I first found in a Hungarian market in Chicago...similar to German kirschwasser and very aromatic.


Venison Bridie Pies

Forfar Bridies are a Scottish meat pie from the town of Forfar. I made mine with puff pastry, and a onion and apple filling with the meat minced by hand. The leftover bits of pastry I tossed on for decoration, realizing only later that they looked a bit like a St. Andrews cross...a lucky accident. A dessert of cranachan (without the usual whisky added, for the rest of the family), which is made from toasted oats, whipped cream, honey, and raspberries, and a glass of Islay whisky (Laphroaig, which is essentially a smoke bomb in a glass) for me. Wildly popular with the family.

I should also show one of my favorite new tools, used to slice frozen meat for my next recipe...my 4" Finnish-made puukko in carbon steel, an utterly lovely knife and certainly the best quality knife I've ever used.


Saseum Bulgogi (사슴 불고기)

That's about the extent of my ability to translate into Korean / Hangul. Sesame-marinated leg steaks of venison, grilled and then sliced, served in lettuce wraps with cucumber, scallions, rice, a dipping sauce, and gochujang, a hot pepper paste.

Venison Sukiyaki

Japanese sukiyaki is normally cooked at the table and eaten as you go. The frozen meat was sliced incredibly thinly (again, thank you, puukko) and we prepared a table with bok choy, mushrooms, tofu, noodles, and scallions, and then fried the meat initially in some sesame oil, adding the sweet soy/sake sauce after, and then adding the vegetables (noodles coming last to absorb the remaining sauce).

The kids enjoyed using their new chopsticks:


Venison Bobotie

I'm not too well versed in the various cuisines of Africa, having taken very amateurish stabs at Moroccan cuisine, and being interested but not experienced in Ethiopian cuisine. South African cuisine appears to be quite the melting pot, integrating native and colonial influences in much the same way that some Caribbean nations do (English, Boer, Bantu, Indian, and Malay influences are all there). Bobotie is an interesting and allegedly iconic dish of South Africa that is similar in some respects to a Shepherd's Pie, but topped with an egg and bay leaf mixture instead of mashed potatoes, and seasoned strongly with curry spices, dried fruit, and chutney. A very piquant dish, balancing sweet and spicy. South African yellow rice, and apricot blatjang (a chutney of sorts made from vinegar and dried apricots among other things) rounded it out, and a small Chicken of the Woods mushroom I found that morning while hiking was sautéed in butter and seasoned with Piri-Piri sauce.

Venison Pierogi

Pierogis are a sort of Polish ravioli, and in some ways surpass their Italian cousins. I did two versions...one, to please the family that clamors for such fillings, a bacon and potato filled pierogi (on the right), and the other, minced venison cooked with onion and dill, and blended with a homemade farmer's cheese. Handmade, boiled until they float, sautéed until slightly browned in bacon fat, and served topped with fried onion. All things in moderation, I suppose...

Poronkäristys Again

Back to Finland to give another shot at this fantastic dish. Another batch of sahti was ready by this time (a little less juniper character than I would prefer....only a few cones on the branches when brewing). Also served were karjalanpiirakat, Karelian savoury pastries made from a hearty rye flour and stuffed with a rice porridge, and pulla, a Finnish slightly-sweet braided bread made with cardamom.

Rajasthani Laal Maans

I've been a student of Indian cooking for many years, and it seemed unlikely that I'd happen across anything close to an authentic recipe for venison in India. However, in the desert state of Rajasthan, game would be taken and served to princes in this fiery, chile-rich dish (the chilies serving to mask any gaminess...which is not something I've noted with my deer). Nowadays Laal Maans is mainly made from goat, but I'm reverting it to its older variation. Served with basmati and layered kalonji paratha.

Hjortfilé med Blåbärsås

The tenderloin is, true to its name, extremely tender, owing to its location along the back on the inside of the vertebrae, where it does little work. We decided to do this one relatively simple using a Swedish venison recipe with a savoury blueberry and red wine sauce. Dill potatoes, cucumber, and some lingonberry ice cream, with it.

Gỏi Thịt Nai

Vietnamese grilled venison salad, with marinated backstrap grilled medium (was aiming for a bit more medium rare, but the children came outside and distracted me) sliced thin atop a bed of greens, peppers, shallots, herbs, and tomato. Served with a lime-soy dipping sauce and dressing, some fresh summer rolls, and a freshly-baked baguette (not pictured).

Venison Stroganov

A Russian classic that has gone somewhat international, a stroganov made with thinly shaved venison and mushrooms in a creamy sauce, bedded on potatoes and served with berry-infused vodka. The Russian black rye bread was hearty and flavored with fennel...the family wasn't as much a fan of that, so I ate that for at least a week as my lunch. The stroganov, on the other hand, was well received, and didn't last long.

Venison Asado

The Argentine tradition of asado is normally a beef-focused affair, but it seemed like a fine way to cook the last of the backstrap...grilled rare over wood with nothing more than salt to season. Sausages (not homemade) thrown in as well.

The picado plate (a sort of appetizer tray of cured meats and cheeses) was popular, as you might expect, although I wasn't a great fan of my chimichurri sauce, which seemed to emulsify. Wine, of course, is a Malbec.

Venison Apple Pasty

As a countering shot to the Argies, I took some of the leftover grilled backstrap and cooked up a British style venison and apple pie (with cheddar and a few minced chanterelles thrown in), not necessarily an emblematic dish of the Falkland Islands, but properly British...and the so-called Islas Malvinas are indeed "properly British"! Some homebrewed cider was on tap, which went well with it.

Carne de Vinho d'Alhos

Off to another island, perhaps a bit more tropical than the chilly Falklands...Madeira. Portuguese-governed and unspeakably beautiful (or so the pictures imply), one of their famed dishes is this meat (usually pork) pickled in acidic wine and garlic, then fried. Pão de Bico is a simple Portuguese bread to accompany, as well as fruit and vinho verde.

By way of trivia, this dish is the etymological origin of the Indian curry vindaloo; the Portuguese brought their cooking style to their colony in Goa, and the traditional dish evolved into vindaloo. You will commonly see Indian restaurants serve potatoes in vindaloo, a mistaken assumption based on the fact that "aloo" is Hindi for potato. In my opinion potatoes have no place in either the Portuguese or Goan dish, it is an accident of false cognates.

Rendang Daging Rusa

Rendang is an Indonesian specialty that holds similarities to Thai curries, but what sets it apart is it is cooked and stewed until the coconut milk boils away, and the spicy meat fries to a dark hue in the separated oil. The combination of sweet, salty, and spicy made this a new favorite for me. Served with jasmine rice, spring rolls, and a chopped salad.

Venison Pirukad

Finland's sourthern neighbor was our next destination, in the Baltic republic of Estonia. Soviet domination seemed to encourage the integration of Russian cultural aspects, and these baked pirukad stuffed with minced venison, bacon, and mushrooms are not unlike Russian pirozhki. Raspberry kissel, somewhere between a drink and a fruit soup or dessert, was beloved by the children, surprise surprise, as was the Estonian kringel, which you could describe as a tarted up cinnamon roll. Washed down with a blackcurrant mead, just bottled recently.

Venison Tortellini

I took my time getting around to what is normally a staple...Italian cuisine...in part because I was planning to do ravioli, and we kept hemming and hawing, whatever that might mean, about whether to buy one of those ravioli crimper things. In the end we decided to skip that and do tortellini, which are a bit like micro-pierogies rolled up into a circle. Served with a roasted red pepper cream sauce (very nearly as simple as it sounds: red peppers blackened over a fire blended with cream and some onion and garlic sauteed in olive oil), insalata caprese, and a Montepulciano d'Abruzzo.

--To Be Continued...not out of venison yet!--