Ich spreche beim #GlobalAzureBootcamp 2017 in Linz über Machine Learning

Es freut mich, bei einem internationalen Event dabei zu sein, ohne lange reisen zu müssen: Das Global Azure Bootcamp findet global am gleichen Tag (heuer am 22. April 2017) in über 240 Location statt – und eben unter anderem in Linz.

Rainer Stropek organisiert das Linzer Event bereits seit einigen Jahren und die wachsende Teilnehmeranzahl zeigt, dass das Theme Cloud im allgemeinen und Microsoft’s Angebot mit Azure im speziellen auf immer mehr Interesse stößt. Heuer ist neu, dass es parallel ein “Junior Bootcamp” gibt – die Gelegenheit, die Konferenz als Eltern-Kind – Tag zu verbringen. 🙂

Ich werde gleich in der Früh (um 9:00) mit einem “Aufruf” starten: “Überlasst das Lernen den Maschinen“. Neben einer Einführung in das “Wie” und “Warum” von “Machine Learning” werden wir gemeinsam einen konkreten Anwendungsfall mit Azure Machine Learning durchspielen. Später am Nachmittag wird dann Rina Ahmed zum gleichen Theme fortsetzen und zeigen, wie Sie Machine Learning in Ihren Anwendungen inkludieren können.

Wir sehen uns in Linz!

Advertisements
Ich spreche beim #GlobalAzureBootcamp 2017 in Linz über Machine Learning

I’m speaking at SQL Saturday Lisbon #sqlsatlisbon

I am looking forward to travel to Lisbon the upcoming weekend. This will be my very first time in Portugal – so I am very excited about the trip.

SQL Saturday Lisbon has invited me to speak about two topics (like roughly all of the accepted speakers – so my first impression about the Portugese is: they bleed us white :-)).

  • A Game of Hierarchies – From GROUP BY to Recursive CTE’s
    This talk covers basically two topics. First, how to apply different GROUP BY clauses to get detailed rows and summary rows in the very same query. Second, how to leverage Common Table Expressions (CTE’s) to visualize so-called parent-child hierarchies. Instead of the “usual” AdventureWorks-demos I invested time to build my own sample database, which is based on George R. R. Martin’s epos “A Game of Thrones”. You should be able to enjoy this session, either if you are interested in SQL solutions to query hierarchies, or if you are interested in the books or the HBO TV show. 🙂
  • My Favorite Pie (Chart): Simple Rules for Clear Visualizations
    In this session I pick up on the discussions if Pie Charts are good or bad on the one hand, and come up with a hand-full guidelines which will help you to check & improve your reports, charts & dashboards on the other hand. In this 60 minutes version of the talk I will not do any classic live demos, but the slides will be filled with good and bad visualisations which I am glad to discuss with you – be prepared for an interactive session. Let’s make Data Visualizations great again! 🙂

I hope I see you in Lisbon!

Sincerly yours,
Markus Ehrenmüller-Jensen

I’m speaking at SQL Saturday Lisbon #sqlsatlisbon

SQL Nexus 2017 in Copenhagen

I am very proud to announce that one of my submissions made it to SQL Nexus 2017 in Copenhagen. (As my wife is danish I feel always partly sort of “home” while being in Denmark – and can apply my danish language skills. And the best part is, that I can use my wife’s Dankort to pay for everything. 🙂 )

I will talk about the power of data vizualisation with the help of R. As visual perception of data is the key to understanding data, being able to plot data is a crucial skill. I will give a broad overview about what R offers on the one hand, and will dive deep into common visualisations on the other hand, so you get scripts at your hand, which you can apply immediatly.

Register soon for the conference, so you secure yourself a seat at an affordable price.

SQL Nexus 2017 in Copenhagen

Speaking in the 2. half of 2016

I am glad that a bunch of upcoming conferences have accepted my submissions. Therefore I have the pleasure of speaking at the following events in the upcoming days, weeks & months:

I also have submitted to SQL Saturdays in Prague (which will be the very first in Czech republic – so be sure not to miss this event) and Slovenia, too, but not heard if they have accepted me as a speaker until now.

And we are already in the middle of organizing the upcoming SQL Saturday in Vienna, which will be held Friday, January 20th 2017 (there will be a pre-con on Thursday, January 19th 2017). Watch out for details!

Speaking in the 2. half of 2016

“NOT” doesn’t negate a boolean expression

During a Slowly Changing Dimension 2-load I stumbled upon a problem, that putting NOT in front of a boolean expression did not negate the result. I first created a condition to find the rows, which had not changed, and then simply put a NOT in front of this condition, expecting that I now get the rows which had been changed. Unfortunately this did not work like as described. Are you curious? Then read on.

First things first. Let’s start with building up a demo environment.

Create a sample table

Create a sample table in TEMPDB and fill it with rows:

--prepare sample table
CREATE TABLE tempdb.dbo.MyDates (
    DestinationDate datetime2,
    SourceDate        datetime2
    )
INSERT INTO tempdb.dbo.MyDates
VALUES
({ts'2016-03-01 12:45:31'}, {ts'2016-03-01 12:45:31'}),
({ts'2016-03-01 12:45:31'}, {ts'2016-04-02 13:15:26'}),
(null,                      {ts'2016-04-02 13:15:26'}),
({ts'2016-03-01 12:45:31'}, null),
(null,                      null)
;

SELECT
    *
FROM
    tempdb.dbo.myDates;


DestinationDate             SourceDate
--------------------------- ---------------------------
2016-03-01 12:45:31.0000000 2016-03-01 12:45:31.0000000
2016-03-01 12:45:31.0000000 2016-04-02 13:15:26.0000000
NULL                        2016-04-02 13:15:26.0000000
2016-03-01 12:45:31.0000000 NULL
NULL                        NULL

Things start out good

Here is, how I started out. First query all rows where DestinationDate and SourceDate matches:

--List rows with identical Date
SELECT
    *
FROM
    tempdb.dbo.myDates
WHERE
    DestinationDate = SourceDate;

DestinationDate             SourceDate
--------------------------- ---------------------------
2016-03-01 12:45:31.0000000 2016-03-01 12:45:31.0000000

As you can see, according to ANSI standard NULL treatment, the row in which both of the columns are NULL are not listed. So we have to add extra-treatment for those rows:

--List rows with identical Date respecting NULL value
SELECT
    *
FROM
    tempdb.dbo.myDates
WHERE
    DestinationDate = SourceDate or
    (DestinationDate is null and SourceDate is null);

DestinationDate             SourceDate
--------------------------- ---------------------------
2016-03-01 12:45:31.0000000 2016-03-01 12:45:31.0000000
NULL                        NULL

Here the trouble begins

Now I have all the rows, which did not change, according to the business logic. I want to get all the rows, which have changed, according to the business logic. So I simply put a NOT in front of my WHERE condition to get “the other” rows:

SELECT
    *
FROM
    tempdb.dbo.myDates
WHERE
    NOT (
    DestinationDate = SourceDate or
    (DestinationDate is null and SourceDate is null)
    );

DestinationDate             SourceDate
--------------------------- ---------------------------
2016-03-01 12:45:31.0000000 2016-04-02 13:15:26.0000000

Wait, a second – there two are rows missing! Putting a simple NOT in front of the previous WHERE condition did not negate the boolean expression. But what is the reason for that? Why doesn’t NOT negate a TRUE to a FALSE and a FALSE to a TRUE?

How to visualize a boolean expression

So I build a query to show me both of the date columns and the result of a boolean expression which compares equality and inequality of both columns.

SELECT
    DestinationDate, 
    SourceDate,
    case
        when     (DestinationDate = SourceDate) then '1'
        else                                         '0'
        end [(DestinationDate = SourceDate)=TRUE?],
    case
        when          (DestinationDate is null) then '1'
        else                                         '0'
        end [(DestinationDate is null)=TRUE?],
    case
        when               (SourceDate is null) then '1'
        else                                         '0'
        end [(SourceDate is null)=TRUE?]

FROM
    tempdb.dbo.myDates;
DestinationDate             SourceDate                  (DestinationDate = SourceDate)=TRUE? (DestinationDate is null)=TRUE? (SourceDate is null)=TRUE?
--------------------------- --------------------------- ------------------------------------ ------------------------------- --------------------------
2016-03-01 12:45:31.0000000 2016-03-01 12:45:31.0000000 1                                    0                               0
2016-03-01 12:45:31.0000000 2016-04-02 13:15:26.0000000 0                                    0                               0
NULL                        2016-04-02 13:15:26.0000000 0                                    1                               0
2016-03-01 12:45:31.0000000 NULL                        0                                    0                               1
NULL                        NULL                        0                                    1                               1

 

And here is the result of the combined condition:

SELECT
    DestinationDate, 
    SourceDate,
    case
        when     (DestinationDate = SourceDate) or (DestinationDate is null and SourceDate is null) then '1'
        else                                                                                             '0'
        end [((DestinationDate = SourceDate) or (DestinationDate is null and SourceDate is null))=TRUE?]

FROM
    tempdb.dbo.myDates;

DestinationDate             SourceDate                  ((DestinationDate = SourceDate) or (DestinationDate is null and SourceDate is null))=TRUE?
--------------------------- --------------------------- ------------------------------------------------------------------------------------------
2016-03-01 12:45:31.0000000 2016-03-01 12:45:31.0000000 1
2016-03-01 12:45:31.0000000 2016-04-02 13:15:26.0000000 0
NULL                        2016-04-02 13:15:26.0000000 0
2016-03-01 12:45:31.0000000 NULL                        0
NULL                        NULL                        1

Everything seems to be fine.

Let’s extend the query by adding columns, which put a NOT in front of those expressions:

SELECT
    DestinationDate, 
    SourceDate,
    case
        when NOT (DestinationDate = SourceDate) then '1'
        else                                         '0'
        end [NOT (DestinationDate = SourceDate)=TRUE?],
    case
        when NOT      (DestinationDate is null) then '1'
        else                                         '0'
        end [NOT (DestinationDate is null)=TRUE?],
    case
        when NOT           (SourceDate is null) then '1'
        else                                         '0'
        end [NOT (SourceDate is null)=TRUE?]

FROM
    tempdb.dbo.myDates;

DestinationDate             SourceDate                  NOT (DestinationDate = SourceDate)=TRUE? NOT (DestinationDate is null)=TRUE? NOT (SourceDate is null)=TRUE?
--------------------------- --------------------------- ---------------------------------------- ----------------------------------- ------------------------------
2016-03-01 12:45:31.0000000 2016-03-01 12:45:31.0000000 0                                        1                                   1
2016-03-01 12:45:31.0000000 2016-04-02 13:15:26.0000000 1                                        1                                   1
NULL                        2016-04-02 13:15:26.0000000 0                                        0                                   1
2016-03-01 12:45:31.0000000 NULL                        0                                        1                                   0
NULL                        NULL                        0                                        0                                   0

Here is the problem again. NOT did not negate/invert the outcome of the condition! “NOT (DestinationDate = SourceDate)=TRUE?” does’nt show the inverted result from “(DestinationDate = SourceDate)=TRUE?”; the last three rows are still not TRUE. This leads to the described unexpected result, which you can see here again:

SELECT
    DestinationDate, 
    SourceDate,
    case
        when NOT (DestinationDate = SourceDate) or (DestinationDate is null and SourceDate is null) then '1'
        else                                                                                             '0'
        end [NOT ((DestinationDate = SourceDate) or (DestinationDate is null and SourceDate is null))=TRUE?]

FROM
    tempdb.dbo.myDates;

DestinationDate             SourceDate                  NOT ((DestinationDate = SourceDate) or (DestinationDate is null and SourceDate is null))=TRUE?
--------------------------- --------------------------- ----------------------------------------------------------------------------------------------
2016-03-01 12:45:31.0000000 2016-03-01 12:45:31.0000000 0
2016-03-01 12:45:31.0000000 2016-04-02 13:15:26.0000000 1
NULL                        2016-04-02 13:15:26.0000000 0
2016-03-01 12:45:31.0000000 NULL                        0
NULL                        NULL                        1

The root cause of trouble

Before the problem is driving you crazy I will show you the root cause of the problem. The root cause is the simple fact, that boolean logic in SQL Server is not implemented as a two-value logic, but as a three-value logic.

Two-value logic would be a simple TRUE and FALSE.

In case of comparisions that means:
‘A’ = ‘A’ –> TRUE
‘A’ = ‘B’ –> FALSE

Negation works fine:
NOT   TRUE –> FALSE
NOT   FALSE –> TRUE

Three-value logic means, that there is, beside TRUE and FALSE, an additional NULL for unknown cases (i will call it UNKNOWN in the following paragraphs).

In case of comparisions that means:
‘A’ = ‘A’ –> TRUE
‘A’ = ‘B’ –> FALSE
‘A’ = null –> UNKNOWN

UNKNOWN means, that the outcome of the condition is neither TRUE nor FALSE. A condition resulting in UNKNOWN in a WHERE-clause will not show the rows. Furthermore, putting a NOT in front of an expression which results as UNKNOWN, stays UNKNOWN, and will not show those rows neither.

NOT   TRUE –> FALSE
NOT   FALSE –> TRUE
NOT   UNKNOWN –> UNKNOWN

You can see the consequences, when I expand the query to show boolean values correctly, respecting the three-value logic:

SELECT
    DestinationDate, 
    SourceDate,

    case
        when     (DestinationDate = SourceDate) then '1'
        when NOT (DestinationDate = SourceDate) then '0'
        else                                         'unknown'
        end [(DestinationDate = SourceDate)=TRUE?],
    case
        when          (DestinationDate is null) then '1'
        when NOT      (DestinationDate is null) then '0'
        else                                         'unknown'
        end [(DestinationDate is null)=TRUE?],
    case
        when               (SourceDate is null) then '1'
        when NOT           (SourceDate is null) then '0'
        else                                         'unknown'
        end [(SourceDate is null)=TRUE?],


     case
        when NOT (DestinationDate = SourceDate) then '1'
        when     (DestinationDate = SourceDate) then '0'
        else                                         'unknown'
        end [NOT (DestinationDate = SourceDate)=TRUE?],

    case
        when NOT (DestinationDate <> SourceDate) then '1'
        when     (DestinationDate <> SourceDate) then '0'
        else                                          'unknown'
        end [NOT (DestinationDate <> SourceDate)=TRUE?]

FROM
    tempdb.dbo.myDates;

DestinationDate             SourceDate                  (DestinationDate = SourceDate)=TRUE? (DestinationDate is null)=TRUE? (SourceDate is null)=TRUE? NOT (DestinationDate = SourceDate)=TRUE? NOT (DestinationDate <> SourceDate)=TRUE?
--------------------------- --------------------------- ------------------------------------ ------------------------------- -------------------------- ---------------------------------------- -----------------------------------------
2016-03-01 12:45:31.0000000 2016-03-01 12:45:31.0000000 1                                    0                               0                          0                                        1
2016-03-01 12:45:31.0000000 2016-04-02 13:15:26.0000000 0                                    0                               0                          1                                        0
NULL                        2016-04-02 13:15:26.0000000 unknown                              1                               0                          unknown                                  unknown
2016-03-01 12:45:31.0000000 NULL                        unknown                              0                               1                          unknown                                  unknown
NULL                        NULL                        unknown                              1                               1                          unknown                                  unknown

 

Now let me sound smart :-):

Not to be TRUE does not mean that something is FALSE. And not to be FALSE does not mean that something is TRUE. As long as there is the UNKNOWN.

Those UNKNOWN values have an impact on boolean AND and OR as well (read NULL as UNKNOWN in the following table):

AND     TRUE    FALSE    NULL
TRUE    TRUE    FALSE    NULL
FALSE   FALSE   FALSE    FALSE
NULL    NULL    FALSE    NULL

When one part of the condition is FALSE, the outcome of the whole condition is FALSE, when combined with AND. Is one part TRUE and the other UNKNOWN, the result becomes UNKNOWN.

OR      TRUE    FALSE    NULL
TRUE    TRUE    TRUE     TRUE
FALSE   TRUE    FALSE    NULL
NULL    TRUE    NULL     NULL

When one part of the condition is TRUE, the outcome of the whole condition is TRUE, when combined with OR. Is one part FALSE and the other UNKNOWN, the result becomes UNKNOWN.


So the NULL values in either DestinationDate or SourceDate lead to a condition resulting as UNKNOWN. Which is OK in the very first example (when either of the two columns is NULL the condition is not TRUE, and the rows will not show up). The problem comes only, when I put a NOT in front of this condition. The condition for those rows (with either of the two date columns being NULL) will stay UNKNOWN and the rows will not be displayed.

Wrap up

Keep always in mind that there is more then TRUE and FALSE for your conditions. Due to a three-value logic of booleans in SQL Server (and most other relational databases) there is an addional UNKNOWN value, which stays UNKNOWN even if you try to negate it with a NOT. Here is the correct solution to find all rows, which have different values for DestinationDate and SourceDate.

SELECT
    *
FROM
    tempdb.dbo.myDates
WHERE
    DestinationDate <> SourceDate or
    (DestinationDate is not null and SourceDate is     null) or
    (DestinationDate is     null and SourceDate is not null);

DestinationDate             SourceDate
--------------------------- ---------------------------
2016-03-01 12:45:31.0000000 2016-04-02 13:15:26.0000000
NULL                        2016-04-02 13:15:26.0000000
2016-03-01 12:45:31.0000000 NULL

Now we get a list of all rows, which have different values for DestinationDate and SourceDate.

And don’t forget to clean up your TEMPDB:

drop table tempdb.dbo.MyDates;

I hope this post helped you a little in understanding the consequences of a three-value boolean logic and how to implement a Slowly Changing Dimension 2-load in case of having to handle NULL values.

Yours sincerly,
Markus Ehrenmueller

“NOT” doesn’t negate a boolean expression

SQLCAT: SQL Server 2016 CollumnStore Customer Scenarios and Best Practices (SQL PASS Summit 2015)

Improve loading a ColumnStore in SQL Server 2016 CTP3 by using the following guidelines:

  • Load into stage-tables per partition using WITH (TABLOCK) and switch those tables in afterwards
  • Separate your INSERT and UPDATE statements
  • For initial load create an empty table with Clustered ColumnStore on it (instead of loading a heap and create the index afterwards)
  • Include the parititioning column in the unique index/primary key (as you would with partitioned heaps)
  • Create statistics immmediately after initial data load (auto stats improvements are on their way, but not implemented yet)
  • Utilize the new possibility to combine Clustered ColumnStore Indexes with b-tree Non-Clustered Indexes where apropriate
  • Clustered ColumnStore Index with a b-tree index on, slows down the load (therefore create the non-clustered b-tree after load; CTP3 allows for parallel non-clustered index creation)
  • REBUILD of ColumnStore is not an online operation, therefore apply it on partition level only
  • Try trace flag 9481 to force the old cardinality estimator for performance-outliers
  • SQL Server Integration Services can lead to trimmed row groups
  • Set AutoAdjustBufferSize on in SQL Server Integration Services to avoid small uncompressed delta stores
  • Use compatibility level 130 when testing ColumnStore
SQLCAT: SQL Server 2016 CollumnStore Customer Scenarios and Best Practices (SQL PASS Summit 2015)

SQL PASS Summit 2015 Keynote #1 (Wednesday)

In 2015 the PASS Summit is the 16th annual meeting of data platform professionals, gathering 5500 total registrations.

PASS President Tom LaRock remembered everybody to welcome #sqlfamily members with a #sqlhug.

Keynote speaker was Joseph Sirosh, Corporte Vice Precident, Data Group.

Analog data will disappear, and digital data got the majority. In short cloud/internet connected data will be the majority. We moved from an age of hardware to an age of software and heading towards an age of data (online recommendations, customer experience, …). Microsofts tool for this is “Cortana Analytics Suite”.

“We are all big data” through 2GB of genomic data.

Eric Fleischman, Chief Architect andVP Platform Engineering, DocuSign, explains how they can cope with the increasing growth of the company, and the data coming with that. Their decision was against open source, as the want to “use” a database system and not “write” a database system.

As averagely two documents are signed every second their system generating 180 Mio events a day.

Engines of data: mission cricital OLTP, high-performance DW, end-to-end mobile BI, with advanced analytics on top of it.

Most of the vendors built their systems (in slow cycles) and ship it afterwards to the cloud. Microsoft is the only company, who builds everything for the cloud and ship it later on-prem. Gartner rated Microsoft as a leader in completeness of vision and completeness of execution.

Shawn Bice, General Manager, Database Systems Group, tells that companies who are able to embrace the data are far more succesful. Big bats:

  • everything is built-in (no add-ins or so)
  • Mission critical OLTP
  • Most secure database: least vulnerable database the past 6 years in a row
  • highest performing data warehouse: won against the other vendors
  • Ent-to-end MobileBI on any device: a fraction of the cost comp (USD 120 against Tableau (USD 480) or Oracle (USD 2230), self-service BI per user)
  • In-database Advanced Analytics: R + in-memory direct to the platofrm
  • in-memory across all workloads
  • consistent experience across cloud and on-prem

Learnings from the experiences with Azure went into SQL 2016 on-prem.

Polybase removes the complexity of big data by enabling T-SQL over Hadoop by providing “external tables” within SQL Server. JSON support will also help a lot of projects.

Real-time is learn and adjust as things are happening. ColumnStore Indexes on top of in-memory (Hekaton) tables will enable this. Combined with embedded R Services the data is accessable to data scientist, without moving the data, but analysing it where it already is.

Rohan Kumar, Partner Director, Engineering shows a showcase with customer “p:cubed”. on a machine with impressive 480 logical processors. Monitors a huge amount of transaction, calculating customer rewards, both in real-time.

Non-Clustered Index will be updateable with SQL 2016. On top of an im-memory table this index will not sacrifice the performance of the oltp-table.

Advanced Analytics enables to include R-scripts within T-SQL code without moving data outside of the data platform and therefore enableing real-time analyitcs. As oltp-data lies in-memory, the data does not even touch the disk from the time it is tracked until it is analyzed.

“Always Encrypted” guarantees, that the encryption key and the deciphered text is available on the client only. The content is never stored in a decrypted way on the server (neither on disk, nor in the buffer pool memory).

Stretch Database allows to combine hot and cold data in one logical table, but actually moves the cold data out to cheaper disks, instead leaving it on the expensive storage, designed for hot data. It will still be queryable in the common way, as the technology is completely transparent to the client. And it works together with “Always Encrypted”.

The stretched part will show up as a “Remote Query” in the execution plan.

Joseph Sirosh: “Our industry does not respect tradition, but does respect innovation.”

Cloud helps to transform hardware to software, software to services and data to intelligence.

Sincerly yours,
Markus Ehrenmüller-Jensen

SQL PASS Summit 2015 Keynote #1 (Wednesday)