User Tracking for Custom Post Type “Lesson”. Database Queries and Performance

Since there are going to be more than one post (lesson) per user, your code would be more like this:

<?php
if ( is_user_logged_in() ) {
    $user_ID = get_current_user_id();
    $post_ID = get_the_ID();
    $viewed = get_user_meta( $user_ID, 'viewed_lesson_tracking', true);
    if(empty($viewed)){
        $viewed = array();
    }
    $viewed[] = $post_ID
    add_user_meta( $user_ID, 'viewed_lesson_tracking', $viewed ); // tracks that user has viewed the current post
}
?>

So, all you have to do, when showing a list of all viewed lessons(posts) is to use the post__in parameter of WP_Query.

WordPress will not loop through the whole table. That’s not how MySQL queries work. At any given time, there’ll only be one query per user. You won’t need to worry about the performance. Plus, WordPress caches all the queries and if you have a cache plugin on top of it, you don’t need to even give it a thought.